Dotnet core 3.0 NativeLibrary

Since the first dotnet core cross platform release, it was a dream that became reality for me to merge the good of multiple worlds.

Many times I need to host a little service to do simple data transfer, and what I prefer is to put it in a small linux dockerized server.

Recently one of my old project SnwConnector emerged from the dust to my attention.

SnwConnector

SnwConnector was a dotnet wrapper of SAP NetWeaver RFC SDK build on top of the old dotnet framework and the Windows x64 SAP native library.

I created the project long time ago, the project was open source and hosted on CodePlex!!!

What I want to do now is to port my library to dotnet core, but keep the ability to be cross-platform, so I could build and test the project on my Windows machine, but keep the opportunity to deploy on a Linux or OSX machine.

NativeLibrary

So it was a good news for me the introduction of NativeLibrary class with dotnet core 3.0.

First I created a Native folder that contains the subfolders with the native library for each platform that I could get from the SAP support center.

After that I add the UnsafeNativeMethods.cs class so by RuntimeInformation you get the type of OSPlatfotm and ProcessArchitecture due the fact that you can force 32bit execution on 64bit architecture.

By these information I can load the right Native library thanks the NativeLibrary.Load(dllPath)

internal static class UnsafeNativeMethods
{
    const string SapNwRfc = "sapnwrfc";

    internal class PlatformDlls
    {
        public string Path { get; set; }
        public string[] DllNames { get; set; }
    }

    static UnsafeNativeMethods()
    {
        PlatformDlls libraryInfo = GetNativeLibraryInfo();
        var path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
        foreach (var dll in libraryInfo.DllNames)
        {
            var dllPath = Path.Combine(path, "Native", libraryInfo.Path, dll);
            NativeLibrary.Load(dllPath);
        }
    }

    private static PlatformDlls GetNativeLibraryInfo()
    {
        PlatformDlls platformDlls = new PlatformDlls();
        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
            && (RuntimeInformation.ProcessArchitecture == Architecture.X64))
        {
            platformDlls.Path = "Win64";
            platformDlls.DllNames = new[] {
                "icudt50.dll",
                "icuin50.dll",
                "icuuc50.dll",
                "libicudecnumber.dll",
                "libsapucum.dll",
                "sapnwrfc.dll"
            };
        }
        else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
            && (RuntimeInformation.ProcessArchitecture == Architecture.X86))
        {
            platformDlls.Path = "Win32";
            platformDlls.DllNames = new[] {
                "icudt50.dll",
                "icuin50.dll",
                "icuuc50.dll",
                "libicudecnumber.dll",
                "libsapucum.dll",
                "sapnwrfc.dll"
            };
        }
        else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)
            && (RuntimeInformation.ProcessArchitecture == Architecture.X64))
        {
            platformDlls.Path = "Linux64";
            platformDlls.DllNames = new[]
            {
                "libicudata.so.50",
                "libicudecnumber.so",
                "libicui18n.so.50",
                "libicuuc.so.50",
                "libsapnwrfc.so",
                "libsapucum.so"
            };
        }
        else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
        {
            platformDlls.Path = "OSX";
            platformDlls.DllNames = new[] {
                "libicudata.50.dylib",
                "libicudecnumber.dylib",
                "libicui18n.50.dylib",
                "libicuuc.50.dylib",
                "libsapnwrfc.dylib",
                "libsapucum.dylib"
            };
        }
        else
        {
            throw new Exception("Unsupported OSPlatform, can't locate sapnwrfc library.");
        }

        return platformDlls;
    }

    //
    // Info API
    //
    [DllImport(SapNwRfc, EntryPoint = "RfcInit")]
    public static extern RfcRc RfcInit();

    [DllImport(SapNwRfc, EntryPoint = "RfcGetVersion")]
    public static extern IntPtr RfcGetVersion(out int majorVersion, out int minorVersion, out int patchLevel);

    //
    // Connection API 
    //
    [DllImport(SapNwRfc, EntryPoint = "RfcOpenConnection")]
    public static extern IntPtr RfcOpenConnection(RfcConnectionParameter[] connectionParams, int paramCount, out RfcErrorInfo errorInfo);

    [DllImport(SapNwRfc, EntryPoint = "RfcCloseConnection")]
    public static extern RfcRc RfcCloseConnection(IntPtr rfcHandle, out RfcErrorInfo errorInfo);

    [DllImport(SapNwRfc, EntryPoint = "RfcPing")]
    public static extern RfcRc RfcPing(IntPtr rfcHandle, out RfcErrorInfo errorInfo);

    [DllImport(SapNwRfc, EntryPoint = "RfcGetConnectionAttributes")]
    public static extern RfcRc RfcGetConnectionAttributes(IntPtr rfcHandle, out RfcAttributes attributes, out RfcErrorInfo errorInfo);

    [DllImport(SapNwRfc, EntryPoint = "RfcSetIniPath", CharSet = CharSet.Unicode)]
    public static extern RfcRc RfcSetIniPath(string pathName, out RfcErrorInfo errorInfo);
}

If you noticed I defined a const SapNwRfc to refer the SAP NetWeaver library used by the attribute DllImport.

You should know that DllImport will search automatically by adding suffixes “.dll” or “.so” or “.dylib” and prefix “lib”.

Tested with the same compiled project by Windows and Linux and it runs!