Fork me on GitHub
#clr
<
2023-01-17
>
djblue08:01:08

I put together a https://github.com/djblue/portal/tree/master/examples/clr#clojure-clr--portal on how to use https://github.com/djblue/portal on clojure clr. Still haven't figured out nuget deps for https://github.com/clojure/clr.data.json, but any feedback is welcome 🙏

🙌 4
4
Anders Eknert10:01:13

That is absolutely awesome! Can’t wait to try it out this weekend 😃

🙌 2
awesome 2
dmiller13:01:50

I'm looking forward to giving it a try. And thanks for doing the work to get this running on ClojureCLR. What problem are you having with clojure.data.json? Assuming you 've used the info below, what's happening? https://www.nuget.org/packages/clojure.data.json

dotnet add package clojure.data.json --version 2.4.0
NuGet\Install-Package clojure.data.json -Version 2.4.0
<PackageReference Include="clojure.data.json" Version="2.4.0" />

bobcalco17:01:31

This looks really useful, especially considering the challenge of debugging generally. I'm impressed with the approach, and the portability of your code.

thanks3 2
bobcalco17:01:44

It would be good to get portal itself on NuGet (@U45FQSBF1 knows the proper incantations and sequence of animal sacrifices required to publish a ClojureCLR library there).

bobcalco17:01:05

Thanks for porting to cljr and providing some clues in the demo how to get it running - working through that now given I have a different setup on my Windoze box.

djblue18:01:57

@U45FQSBF1 I can get clojure.data.json working locally, but I'm not sure how transitive dependencies are suppose to work for the clr, especially with the odd way in my guide which uses a deps.edn + clojure cli 😅

djblue18:01:44

@U2M7EC8KU I am looking into publishing a dll, but my first attempt was not successful 😆 I tried out some of the steps in https://github.com/clojure/clojure-clr/blob/master/docs/nuget-for-libs.md but I don't know how to inspect the dll to verify that the clojure source was bundled correctly :thinking_face:

dmiller18:01:47

nuget should pull in the dependencies. However, clojure cli doesn't understand that.

djblue18:01:19

So if I get portal packaged up as a dll and published to nugget, transitive dependencies should automatically resolve?

dmiller18:01:05

I think so. nuget-for-libs is definitely written more to remind me what I did the last time than with an eye to being a good user guide. I usually use ILSpy to peek inside the DLL. I'm sure there are better ways but haven't done the research.

🙏 2
dmiller18:01:48

I did find someone recommending just opening the DLL in Notepad++ and see what's there. Not too much binary noise for these DLLs. But rather crude.

😂 4
dangercoder15:01:55

I'm executing some code via the REPL and I'm having issues with using this extension method: https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.builder.endpointroutebuilderextensions.mapget?view=aspnetcore-7.0#microsoft-aspnetcore-builder-endpointroutebuilderextensions-mapget(microsoft-aspnetcore-routing-iendpointroutebuilder-system-string-microsoft-aspnetcore-http-requestdelegate) I'm getting the following error, but the class I'm using is implementing the interface that the C# extension method needs. Microsoft.Scripting.ArgumentTypeException: "expected IEndpointRouteBuilder, got WebApplication" (EndpointRouteBuilderExtensions/MapGet ^WebApplication app "/country/cities" request-delegate) (-&gt; (WebApplication/CreateBuilder) (.Build) class (.GetInterfaces)) > (Microsoft.Extensions.Hosting.IHost System.IDisposable Microsoft.AspNetCore.Builder.IApplicationBuilder Microsoft.AspNetCore.Routing.IEndpointRouteBuilder System.IAsyncDisposable) Am I missing some interop thing? I was expecting the compiler to pass on the interface information. I tried annotating app with IEndpointRouteBuilder but that throws an error runtime.

dmiller16:01:15

I would have thought calling MapGet as a static as you have done here, with the type annotation would have done the trick. I don't know why the annotation would throw an error. Do you have an absolute minimum setup to get to that MapGet call that I could work with?

dangercoder18:01:47

(I just updated the repo the repl works again, accidently cleaned up a bit too much;)

dmiller18:01:07

What system DLLs do I need to load first?

dangercoder18:01:11

facepalm I had forgotten to add src/clj_api/user.clj. Try now, if you run dotnet-script main.csx it will load it for you

dangercoder18:01:53

using dotnet-script was the only was I could manage to load all required dll's. Let me know if it works 🙂. Good to know: This repo loads dll's by these directories (im on ubuntu): /usr/share/dotnet/shared/Microsoft.AspNetCore.App/6.0.13 /usr/share/dotnet/shared/Microsoft.NETCore.App/6.0.13

dmiller18:01:31

I don't think my windows box has /usr/share available unless I drop into WSL. 🙂 But I'll cope.

dangercoder18:01:51

I'll make it load these DLLs by the current assembly location later. I was just keen on getting something out there that "kind of works"

dangercoder19:01:29

@U45FQSBF1feel free to pull, I've made user.clj load the assemblies dynamically instead of a hardcoded path:slightly_smiling_face:

dmiller19:01:42

I'm getting some weird behavior. I pulled in the DLLs from the two directories, adjusted for my box. main.clj fails to load due to an import failing. I did each import by hand. It fails only WebApplication. This is totally bizarre, because it can find WebApplicationBuilder from the same namespace. This is very puzzling. So I thought I'd list the types in assembly Microsft.AspNetCore.dll. And it blows up. It blows up calling GetTypes on the assembly.

(def assy (first  (filter #(= (.Name (.GetName %)) "Microsoft.AspNetCore") (.GetAssemblies AppDomain/CurrentDomain))))

(.GetType assy "Microsoft.AspNetCore.Builder.WebApplicationBuilder")  ; => Microsoft.AspNetCore.Builder.WebApplicationBuilder

(.GetType assy "Microsoft.AspNetCore.Builder.WebApplication")  ; => nil

(.GetType assy "Microsoft.AspNetCore.Builder.EndpointRouteBuilderExtensions") ; => nil

(import '[Microsoft.AspNetCore.Builder EndpointRouteBuilderExtensions]) ; => Microsoft.AspNetCore.Builder.EndpointRouteBuilderExtensions

(import '[Microsoft.AspNetCore.Builder WebApplication])   ; => Bad type

user=> (def types (.GetTypes assy))

Execution error (ReflectionTypeLoadException) at System.Diagnostics.StackFrame/GetTypes (NO_FILE:0).
Unable to load one or more of the requested types.
[I've cut this down to just the names]

 'Microsoft.Extensions.Options, 
 'Microsoft.AspNetCore.Hosting.Abstractions, 
 'Microsoft.AspNetCore.Hosting.Abstractions, 
 'Microsoft.Extensions.DependencyInjection.Abstractions,
 'Microsoft.Extensions.Configuration.Abstractions,
 'Microsoft.Extensions.Hosting.Abstractions, 
 'Microsoft.AspNetCore.Hosting.Abstractions, 
 'Microsoft.Extensions.Configuration.Abstractions, 
 'Microsoft.Extensions.Hosting.Abstractions, 
 'Microsoft.Extensions.Hosting.Abstractions, 
 'Microsoft.Extensions.Configuration.Abstractions, 
 'Microsoft.Extensions.Logging, 
 'Microsoft.Extensions.Hosting.Abstractions, 
 'Microsoft.Extensions.Configuration.Abstractions, 
These are direct calls to system methods, so the problem is underneath. What is missing?

dangercoder19:01:22

I was stuck on the exact same thing, that's why I made an ugly solution. I made clojure boot via: https://github.com/Dangercoder/clojure-clr-dotnet-api/blob/master/src/main.csx in order to do that you need to cd into src and execute dotnet-script main.csx

dangercoder22:01:21

I made a small hack in main.csx make it work for now.

var app = WebApplication.Create();
IFn state = Clojure.var("user", "add-state");
state.invoke(app);
add-state adds an instance of WebApplication to an atom in the user namespace. Now (EndpointRouteBuilderExtensions/MapGet ^WebApplication app "/country/cities" request-delegate) works.

dmiller22:01:38

I can get it running with that script. Very neat. I have a partial answer to the problem, and you can probably use it fix your situation. I do not understand why it occurs. The problem is that there is more than one IEndpointRouteBuilder type. The one that you have imported and that you get when you use the nakedly is not the same as the Microsoft.AspNetCore.Builder.IEndpointRouteBuilder that is implemented by WebApplication !?!

clj-api.main=> (def wa WebApplication)
#'clj-api.main/wa
clj-api.main=> (def ii (.GetInterfaces wa))
#'clj-api.main/ii
clj-api.main=> ii
(Microsoft.Extensions.Hosting.IHost System.IDisposable Microsoft.AspNetCore.Builder.IApplicationBuilder Microsoft.AspNetCore.Routing.IEndpointRouteBuilder System.IAsyncDisposable)
clj-api.main=> (def ierb (nth ii 3))
#'clj-api.main/ierb
clj-api.main=> ierb
Microsoft.AspNetCore.Routing.IEndpointRouteBuilder
clj-api.main=> (= ierb IEndpointRouteBuilder)
false
The have the same assembly-qualified names:
clj-api.main=> (.AssemblyQualifiedName IEndpointRouteBuilder)
"Microsoft.AspNetCore.Routing.IEndpointRouteBuilder, Microsoft.AspNetCore.Routing, Version=7.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60"

clj-api.main=> (.AssemblyQualifiedName ierb)
"Microsoft.AspNetCore.Routing.IEndpointRouteBuilder, Microsoft.AspNetCore.Routing, Version=7.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60"
However, a WebApplication object implements one of them and not the other.
clj-api.main=> (class a)
Microsoft.AspNetCore.Builder.WebApplication
clj-api.main=> (.IsInstanceOfType IEndpointRouteBuilder a)
false
clj-api.main=> (.IsInstanceOfType ierb a)
true
How is this possible? They are defined in different assemblies.
clj-api.main=> (.Assembly ierb)
#object[RuntimeAssembly 0x3ca82c3 "Microsoft.AspNetCore.Routing, Version=7.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60"]
clj-api.main=> (.Assembly IEndpointRouteBuilder)
#object[RuntimeAssembly 0x21e98db "Microsoft.AspNetCore.Routing, Version=7.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60"]
clj-api.main=> (= *1 *2)
false
Somehow, the assembly is getting loaded twice. I do not know how that is possible.

dmiller22:01:33

Well, there are some hints on how that is possible. Assembly.LoadFile could be the culprit. LoadFile loads into a different context than Assembly.Load. see here for an instance of this occurring: https://github.com/dotnet/runtime/issues/39783 And you are using assembly-load-file in your user.clj.

💡 2
dangercoder22:01:26

@U45FQSBF1 thanks for looking into this, I really appreciate it. It's cool to hack some .NET with clojure-clr 😄

dmiller22:01:35

Totally. I don't have time to hack it right now, but test out replacing your assembly-load-file. Let me know. And I'll be interested in the end-result of this project, so please keep me informed.

dmiller00:01:26

Changed assembly-load-file to assembly-load-from. (You should probably use assembly-load, but you need to provide long form names, I think, and I was too lazy to experiment.)

C:\work\temp\clojure-clr-dotnet-api\src>dotnet-script main.csx
Loading user.clj
Loading assemblies in:  C:\Program Files\dotnet\shared\\7.0.0
Loading assemblies in:  C:\Program Files\dotnet\shared\\7.0.0
Clojure 1.12.0-alpha3
user=> (load "clj_api/main")
nil
user=> (in-ns 'clj-api.main)
#object[Namespace 0x1952e60 "clj-api.main"]
clj-api.main=>
clj-api.main=>   (def app (-> (WebApplication/CreateBuilder)
               (.Build)
               configure-app))
#'clj-api.main/app
clj-api.main=>
That counts as success?

dangercoder07:01:59

It does. I also managed to remove main.csx and still get WebApplication to load by using assembly-load-from . I can now execute my program using the Clojure.Main tool 🎉

dmiller16:01:08

I have been working on side project to think about rewriting ClojureCLR with an eye to improving the compiler and interop. I've started writing some posts about the code analysis and thoughts on design. Right now I'm working through how to restructure the monolith to reduce cyclic dependency in the code. In other words, a real laugh riot. I'm writing up things mostly for myself--it helps clarify my thinking--and perhaps, if this project ever makes it into production, for some future maintainer(s). But I'll mention it here anyway. https://dmiller.github.io/clojure-clr-next/

👍 8
2
bobcalco17:01:59

Count me on board on this project! Very exciting. BTW, did anything ever happen vis a vis the once-and-future Lokad/ILPack release with the PR you submitted?

dmiller18:01:24

Nope. I'm going to have fork it and see if it works. Last response I saw from them to a recent bug report was 'thanks, no resources to work on it at this time.' I'll see what I can do this week.

dmiller20:01:27

# posts now = 11. I'm going to have to slow down to write some code instead of prose.