Henk Mollema
Henk Mollema

Reputation: 46491

Dynamically load assemblies in ASP.NET 5

I used to have some code which scanned the bin directory of my application for assemblies which weren't loaded in the AppDomain yet and loaded them. It basically looked like:

foreach (var assemblyPath in Directory.GetFiles("path\to\bin", "*.dll"))
{
    var inspected = Assembly.ReflectionOnlyLoadFrom(assemblyPath);
    Assembly.Load(inspected.GetName());
}

I skipped the try/catch clauses, etc for brevity.

This allowed me to drop assemblies in the bin folder at run-time with implementations for certain interfaces and let the IoC container pick them up automatically. Now with the new Roslyn magic, there are no physical DLL's anymore when debugging. Is there any way to retrieve assembly names, project names or dependency names (in project.json) dynamically.

I guess I have to implement something like this example in the Entropy repo, but I don't know how to implement it for my scenario.

Upvotes: 5

Views: 7880

Answers (5)

Miguel Tomás
Miguel Tomás

Reputation: 1911

Its not ASP.NET but it can be converted easily to asp.net. bellow if function for loading an assembly, and invoke a method inside a class on that assembly.

        private static FormCustomized loadLayout(global::System.String layoutFilename, global::System.String layoutNameSpace)
    {
        FormCustomized mainForm = default;
        Type typeMainLayout = default;
        FileInfo layoutFile;
        layoutFile = new FileInfo(layoutFilename);
        layoutFile.Refresh();
        if (!layoutFile.Exists)
        {
            MessageBox.Show("Layout file not found. You need to reinstall the program");
            return default;
        }

        try
        {
            Assembly assemblyRaw = Assembly.LoadFrom(layoutFilename);
            AssemblyLoadContext context = AssemblyLoadContext.Default;
            Assembly assembly = context.LoadFromAssemblyPath(layoutFilename);


            Type typeMainLayoutIni = assembly.GetType(layoutNameSpace + ".initializeLayoutClass");
            Object iniClass = Activator.CreateInstance(typeMainLayoutIni, true);
            MethodInfo methodInfo = typeMainLayoutIni.GetMethod("AssembliesToLoadAtStart");
            enVars.assemblies = (Dictionary<string, Environment.environmentAssembliesClass>)methodInfo.Invoke(iniClass, default);
            typeMainLayout = assembly.GetType(layoutNameSpace + ".mainAppLayoutForm");
            mainForm = Activator.CreateInstance(typeMainLayout, enVars) as FormCustomized;
        }
        catch (Exception ex)
        {
            return default;
        }

        return default;
    }

Upvotes: 0

Gary Holland
Gary Holland

Reputation: 2645

For .net core users, here is my code for loading assemblies from a specific path. I had to use directives, as it's slightly different for .Net Framework and .Net Core.

In your class header you'll need to declare the using something similar to:

#if NET46
#else
    using System.Runtime.Loader;
#endif

And in your function something similar to the following:

string assemblyPath = "c:\temp\assmebly.dll";

#if NET46
                Assembly assembly = Assembly.LoadFrom(assemblyPath);
#else
                AssemblyLoadContext context = AssemblyLoadContext.Default;
                Assembly assembly = context.LoadFromAssemblyPath(assemblyPath);
#endif

Upvotes: 0

Henk Mollema
Henk Mollema

Reputation: 46491

I solved this issue partly using the ILibraryManager as suggested by @tugberk. I changed the approach a bit which dropped the need of scanning the bin folder for new assemblies. I just want all the loaded assemblies in the current AppDomain.

I injected an instance of the ILibraryManager interface in my type finder class and used the GetReferencingLibraries() method with the name of the core assembly, which is referenced by all the other assemblies in the application.

A sample implementation can be found here, where this is the important part:

public IEnumerable<Assembly> GetLoadedAssemblies()
{
    return _libraryManager.GetReferencingLibraries(_coreAssemblyName.Name)
                          .SelectMany(info => info.Assemblies)
                          .Select(info => Assembly.Load(new AssemblyName(info.Name)));
}

Upvotes: 1

Jonas Lundgren
Jonas Lundgren

Reputation: 1031

You can use the IAssemblyLoadContextAccessor interface to load ASP.NET 5 class library (.xproj) projects dynamically. The following example code works with Beta 4:

public class Startup
{
    public void Configure(IApplicationBuilder app)
    {
        var assemblyLoadContextAccessor = app.ApplicationServices.GetService<IAssemblyLoadContextAccessor>();
        var loadContext = assemblyLoadContextAccessor.Default;
        var loadedAssembly = loadContext.Load("NameOfYourLibrary");
    }
}

Upvotes: 6

tugberk
tugberk

Reputation: 58434

What you are looking for is ILibraryManager implementation which provides access to the complete graph of dependencies for the application. This is already flowed through the ASP.NET 5 DI system. So, you can reach out to it from there.

Sample usage can be found inside RoslynCompilationService.

Upvotes: 3

Related Questions