Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to update an assembly shared between .NET Core and .NET Framework applications

I have Application A that is developed in .NET Core 2.1 and Application B that is developed in .NET Framework 4.7.1. They have a shared library/assembly that is developed using .NET Standard 2.0. This works great, I can compile a single instance of this library and share it between Application A and Application B. But this requires two copies of the assembly in each applications bin folder. If Application A and Application B are deployed on the same machine I would like to update a single instance of the shared assembly in a single location and have both Application A and Application B updated. Is there a way that Application A and Application B can look in the same location for this assembly given that one is using .NET Core and the other is using .NET Framework?

like image 873
Kevin Junghans Avatar asked Sep 05 '18 19:09

Kevin Junghans


1 Answers

Steve pointed me in the right direction with his comment. Here is the complete answer with examples. I wrote a simple console application in .NET Core and .NET Framework that calls a shared library. The library just returns the version number of the library to display in the console application. This will make the testing easier, as you will see. Here is all the shared library does.

using System.Diagnostics;

namespace MyLibrary
{
    /// <summary>
    /// This is a shared library that returns the assemblies version
    /// </summary>
    public class SharedLib
    {
        public string GetProductVersion()
        {
            System.Reflection.Assembly assembly = 
              System.Reflection.Assembly.GetExecutingAssembly();
            FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(assembly.Location);
            string version = fvi.ProductVersion;
            return version;
        }
    }
 }

The shared library is compiled targeting .net standard 2.0. For my test I published it as a NuGet package on a local NuGet server. I then included the NuGet package in the Core and Framework Applications. Both application are pretty much identical. Here is the code.

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Registering Resolving Handler...");
        AppDomain.CurrentDomain.AssemblyResolve += MyHandler;
        Console.WriteLine("Creating shared library...");
        SharedLibWrapper sharedLib = new SharedLibWrapper();
        Console.WriteLine("The version is {0}", sharedLib.Version);
        Console.WriteLine("Press Enter key to continue...");
        Console.ReadLine();

    }

    static string GetSharedAssemblyPath()
    {
        string relativePath = @"..\..\..\SharedAssemblies\";
        return Path.GetFullPath(relativePath);
    }

    static Assembly MyHandler(object source, ResolveEventArgs e)
    {
        Console.WriteLine("Resolving {0}", e.Name);
        if (e.Name.Contains("MyLibrary"))
        {
            string path = GetSharedAssemblyPath() + @"MyLibrary.dll";
            Console.WriteLine("Resolving to path {0}", path);
            return Assembly.LoadFile(path);
        }
        return null;
    }
}

This code adds an AssemblyResolve handler so that in the event the application cannot find the assembly the handler will try to resolve it. In this case I have both application look in a SharedAssemblies folder located at the root of solution.

You will notice that I put the shared library in a class wrapper. This was the only way I could get the solution to work. If I referenced the shared library directly in Main method the application attempts to load the assembly before registration of the event handler occurs.

Now when I compile the applications and run them I get the following output.

Registering Resolving Handler...

Creating shared library...

The version is 1.0.10765

Press Enter key to continue...

Now lets put a new version of shared library in the SharedAssemblies folder and delete the one published with the application. Now this is the output.

Creating shared library...

Resolving MyLibrary, Version=1.0.10765.0, Culture=neutral, PublicKeyToken=null

Resolving to path C:...\SharedLibrary\SharedAssemblies\MyLibrary.dll

The version is 1.0.10930

Press Enter key to continue...

The results are the same for Core and Framework applications. Notice that we can drop a newer version of the assembly in the SharedAssemblies folder and it still loads correctly. This is the result I was looking for to allow for updates of the shared library. Now I can drop it in one location and update both applications. But if I want to only update one application for some reason I still can by just putting the desired version in bin folder for the application. This works because the assembly resolver will look in the local bin first and only pull from the shared location if not found there.

You can get all of the source code to play with this on this GitHub project.

like image 140
Kevin Junghans Avatar answered Oct 01 '22 13:10

Kevin Junghans