Interoperability with .NET

We have some Dimension Selector built in .NET which i want to invoke from Julia. IS there any Julia to .NET interoperability tools?

I have used R.NET for R to .NET connection and Pythonnet for Python to .NET connection. So looking to see if anything similar is available for Julia to .NET.

3 Likes

Not that I’m aware of. I agree, it would be super cool if there was a package that provided interop with .Net, there is a lot of cool software out there on that platform!

And with .Net Core it should be quite simple to a) make that work on all platforms, not just Windows, and b) completely self-host .Net, i.e. have a private installation in the interop package, no dependency on anything systemwide etc.

PS: This probably doesn’t belong in this discourse section, it seems entirely unrelated to VS Code. Maybe one of the mods can move the thread?

1 Like

Moved to Usage.

Yes, such a package for .NET interop would be great.
For a optimization project with some complex GUI I am currently working on a C# application calling julia like this:

    class Julia
    {
        [DllImport("kernel32.dll")]
        public static extern bool SetDllDirectory(string pathName);

        [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)]
        public static extern void jl_init(string julia_home_dir);

        [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)]
        public static extern IntPtr jl_eval_string(string str);

        //[DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)]
        //public static extern IntPtr jl_box_float64(float value);

        //[DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)]
        //public static extern double jl_unbox_float64(IntPtr value);

        [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)]
        public static extern void jl_atexit_hook(int a);

        //[DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)]
        //public static extern IntPtr jl_array_data(IntPtr value);

        public static void julia()
        {
            SetDllDirectory(@"c:\Program Files\Julia-0.6.2\bin\");

            jl_init(@"c:\Program Files\Julia-0.6.2\bin\");

            jl_eval_string("[\"2\" \"3\" \"4\"]");
            jl_eval_string("write(\"test.out\",\"helloxx2\");");
            jl_eval_string("println(\"test.out\"*\"hello2\");");

            jl_atexit_hook(0);
        }
    }

Still experimenting with it, with not so much success.

2 Likes

Any updates here ? :smiley:

Currently I succeeded only with julia 0.6.2 with the following code in MS Visual Studio Community 2017 Version 15.9.12 and .NET Framework Version 4.7.03190:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;

namespace julia
{
    class NativeMethods
    {
        
        [DllImport("kernel32.dll")]
        public static extern bool SetDllDirectory(string pathName);

        [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)]
        private static extern void jl_init(string julia_home_dir);

        [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)]
        private static extern IntPtr jl_eval_string(string str);

        [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)]
        public static extern void jl_atexit_hook(int a);

        public static void Julia( string juliaDir, string juliaScriptDir, string projectPath )
        {
            
            SetDllDirectory(juliaDir);

            jl_init(juliaDir);

            string script = (juliaScriptDir + "myJulia.jl").Replace(@"\",@"\\");
            jl_eval_string("include(\"" + script + "\");");

            jl_atexit_hook(0);


        }
    }
}

The parameters are

string juliaDir = "d:\\Temp\\julia-0.6.2\\bin\\"
string juliaScriptDir = "d:\\Temp\\julia-bin\\"

string projectPath is not used yet.

Calling

julia.NativeMethods.Julia(juliaDir, juliaScriptDir, projectPath);

runs myJulia.jl in ...\bin\x64\Debug\ which is the debug working folder of the Visual Studio project.

2 Likes

Great, thank you. Do you have this project on Github ?

I used the same code as you in .NET Core 3.0 and Julia 1.3-DEV and got this

System.EntryPointNotFoundException: 'Unable to find an entry point named 'jl_init' in DLL 'libjulia.dll'.'

Does anybody have an idea of what might be wrong ?

I searched the internet, found some stuff related to the creation of libjulia.def and libjulia.lib followed the tutorials and all but it still throws the same error.

I’ve also tried to change the signature of jl_init because i’ve noticed that there is only one jl_init() in this version which is

JL_DLLEXPORT void jl_init(void);

but no success

You probably need to use the symbol jl_init__threading, which is the real function name behind a C preprocessor jl_init macro: https://github.com/JuliaLang/julia/blob/cef655a68a4e824cbe7cca582256d61aa72eb725/src/julia.h#L1516-L1518

3 Likes

It worked! you’re a genious!! Thank you.

Thanks a lot. This was the missing link to use c# with julia 1.x.x

I had a hard time now struggling with running a Julia script via include("...") from my C# GUI.
There wasn’t a problem when using Julia 0.6 but with 1.1 it failed silently.

Finally I found a solution and during my way to it I was able to get some exception string from the Julia call.
This is now my current code to call Julia 1.1 (or above) and run a Julia script from C#:

using System;

using System.Runtime.InteropServices;
using System.IO;

namespace julia
{
    class NativeMethods
    {
        
        [DllImport("kernel32.dll")]
        public static extern bool SetDllDirectory(string pathName);

        [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)]
        private static extern void jl_init__threading();

        [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)]
        private static extern IntPtr jl_eval_string(string str);

        [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)]
        private static extern IntPtr jl_exception_occurred();

        [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)]
        private static extern IntPtr jl_typeof_str(IntPtr value);

        [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)]
        public static extern void jl_atexit_hook(int a);

        public static void Julia(string juliaDir, string juliaScriptDir, string projectPath)
        {
            SetDllDirectory(juliaDir);

            jl_init__threading();

            string script = @"Base.include(Base,raw""d:\Temp\test.jl"";)";
            //string script = @"include(raw""d:\Temp\test.jl"";)";
            jl_eval_string(script);
            IntPtr exception = jl_exception_occurred();
            if (exception != (IntPtr)0x0)
            {
                string exceptionString = System.Runtime.InteropServices.Marshal.PtrToStringAnsi(jl_typeof_str(jl_exception_occurred()));
                Console.WriteLine(exceptionString);
            }

            jl_atexit_hook(0);
        }
    }
}

If you use the out-commented statement

string script = @"include(raw""d:\Temp\test.jl"";)";

the exceptionString will be "UndefVarError" and the script will not run.

The call is

julia.NativeMethods.Julia(juliaDir, juliaScriptDir, projectPath);

Parameter juliaDir must be the folder where libjulia.dll resides, e.g. c:\\Programs\\Julia-1.1.0\\bin\\.

The other two paramers (juliaScriptDir and projectPath) are not used in this example.

1 Like

Hi Guys, have any of you ever tried/managed to build/publish a self-container C# application with Julia embedded ? If yes, could you give me a direction ?

Cheers

I am currently on this, I guess, but I am not sure what you mean with “a self-container C# application with Julia embedded”. Can you elaborate?

Hi @oheil, sure, by self-contained c# application i mean the usual .NET Core self-contained publish step that ships the .NET core runtime, i was wondering if we could also ship the Julia runtime along and have both languages packaged into this self-contained published .exe.

Example, when we publish any .NET core application it packages a bunch of System.XXX.dll like System.Collections.dll, i was wondering if we could also package the libjulia.dlls and it’s dependencies in order to have everything in one package, i think this would allow for very powerful applications.

Ah, ok. No, I am not this far with my application yet. When it comes to publishing everything using a installer my thoughts were on NSIS just because I used it before.
I will check this out when times come but I expect some month to come .

Ah ok, i was just wondering the applicability of this approach since PackageCompiler.jl is not very nice yet. I think my problem is the fact that distributing a Julia application is so hard right now, maybe merging it with C# could mitigate this.

I recently got some likes on this thread, so I opened it again to see what I did here.
The project I worked on is publicly available: https://github.com/oheil/doTimeTable/
and shows how Julia can be embedded in a complete C# application installer. Which means, installing the application is all the user needs to do (no preinstalling of Julia or something like that).
The link from C# to Julia is mainly in GUI/doTimeTable/Julia.cs. Julia is called in a separate thread.

9 Likes

Nice work oheil. I had to figure this out at a previous job - it was not fun.

Note: Repost to give greater detail

Here is my library on Julia & .NET Interoperability: GitHub - HyperSphereStudio/JULIA.Net

It uses the C-Interface of both languages to translate between the languages very quickly compared to normal server/client based systems.

 Julia.Init();
  JLFun fun = Julia.Eval("t(x) = sqrt(x)");
  double result = (double) fun.Invoke(2);
  object dotNetObject = fun.Invoke(3).Value;
  Julia.Exit(0);  

It is very new but it has support for various built in Julia features such as a JLArray to allow manipulating jl_arrays neatly.

You can also work with .NET from Julia (Experimental at the moment). It utilizes .NET reflection

In C#:

public class TestClass{
    public long g;
    public TestClass(long g) => this.g = g;
}

Working from Julia:

sharpType = SharpType("TestClass")  #Retrieve Type
sharpCon = SharpConstructor(sharpType, 0)  #Get Constructor at Index 0
o = sharpCon(6) #Create Instance
sharpField = SharpField(sharpType, "g") #Get Field
println(sharpField(o)) #Get Field Value
8 Likes