Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Autofac: How to load assemblies that are referenced but not directly used

We have created a WebApi solution using Autofac for DI. We broke out the bootstrapping of our autofac into a separate project. This way, our WebApi project only references our Bootstrap and Contracts projects. Our bootstrap project then references all other assemblies and wires everything together. I like this design for separation of concerns.

We can manually load our assemblies as follows - where our "AutofacModule" classes contain the necessary info to register each module (assembly).

ContainerBuilder builder = new Autofac.ContainerBuilder();
builder.RegisterModule(new Business.AutofacModule());
builder.RegisterModule(new Data.AutofacModule());
builder.RegisterModule(new Services.AutofacModule());
etc...

This works, but requires hardcoding each assembly. We are trying to make this dynamic so that we can just loop over all referenced assemblies as follows.

var assemblies = BuildManager.GetReferencedAssemblies().Cast<Assembly>();
foreach (var assembly in assemblies)
{
    builder.RegisterAssemblyModules(assembly);
}

This should work but doesn't. The problem is that .Net determines various assemblies aren't actually used from within the bootstrap project and doesn't load them (in an attempt to optimize?). So some of our assemblies are never loaded.

I have also tried the following to loop through the bin directory to find all assemblies. However, during compilation, .Net doesn't move the non-referenced assemblies into the bin directory, so they aren't there either.

string assemblyPath = System.IO.Path.Combine(
    System.AppDomain.CurrentDomain.BaseDirectory, "bin");
var allAssemblies = new List<Assembly>();
foreach (string dll in Directory.GetFiles(assemblyPath, "*.dll"))
{
    allAssemblies.Add(Assembly.LoadFile(dll));
}

I have set the assemblies to Copy Local which didn't work. I read about a Copy Local bug and tried workarounds for that which didn't work either.

Has anyone been able to solve this issue? It seems like Autofac would provide a solution, but all I found was a To Do page on their documents: http://autofac.readthedocs.org/en/latest/faq/isolate-autofac.html

The following two questions are similar, but none of the proposed solutions overcome the fact that the needed assemblies are not in the bin directory.

Not all assemblies are being loaded into AppDomain from the bin folder

Loading all referenced assemblies .NET even if not used explicitly in code

Finally, I'm curious, is this an Autofac specific problem? How do other DI containers solve this problem? I found a similar problem for NInject. Loading unreferenced dll MVC Ninject

like image 449
Francisco d'Anconia Avatar asked Nov 19 '15 17:11

Francisco d'Anconia


People also ask

Is Autofac A IoC?

Autofac is an IoC container for Microsoft . NET. It manages the dependencies between classes so that applications stay easy to change as they grow in size and complexity.

Why should I use Autofac?

AutoFac provides better integration for the ASP.NET MVC framework and is developed using Google code. AutoFac manages the dependencies of classes so that the application may be easy to change when it is scaled up in size and complexity.

How do I register an Autofac service?

Register by Type var builder = new ContainerBuilder(); builder. RegisterType<ConsoleLogger>(); builder. RegisterType(typeof(ConfigReader)); When using reflection-based components, Autofac automatically uses the constructor for your class with the most parameters that are able to be obtained from the container.


2 Answers

This should help you. It takes all the assemblies in the bin folder, starting with name MyModule.

   //builder.RegisterType(typeof(IFoo)).AsImplementedInterfaces();
        ContainerBuilder builder = new ContainerBuilder();

        string[] assemblyScanerPattern = new[] { @"MyModule.*.dll"};

        // Make sure process paths are sane...
        Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory);

        //  begin setup of autofac >>

        // 1. Scan for assemblies containing autofac modules in the bin folder
        List<Assembly> assemblies = new List<Assembly>();
        assemblies.AddRange(
            Directory.EnumerateFiles(Directory.GetCurrentDirectory(), "*.dll", SearchOption.AllDirectories)
                     .Where(filename => assemblyScanerPattern.Any(pattern => Regex.IsMatch(filename, pattern)))
                     .Select(Assembly.LoadFrom)
            );


        foreach (var assembly in assemblies)
        {
            builder.RegisterAssemblyTypes(assembly )
                .AsImplementedInterfaces();
        }
        var container = builder.Build();

This will load those assemblies also which are not even referenced.

like image 78
Parminder Avatar answered Nov 13 '22 13:11

Parminder


var assemblies = Directory.EnumerateFiles(AppDomain.CurrentDomain.BaseDirectory, "*.dll", SearchOption.TopDirectoryOnly)
   .Where(filePath => Path.GetFileName(filePath).StartsWith("your name space"))
   .Select(Assembly.LoadFrom);

var builder = new ContainerBuilder();

builder.RegisterAssemblyTypes(assemblies.ToArray())
   .Where(t => typeof(ITransientDependency).IsAssignableFrom(t))
   .AsImplementedInterfaces();
like image 45
hungryMind Avatar answered Nov 13 '22 14:11

hungryMind