14

I've started using Autofac and want to scan some DLL's and get Autofac to register some of the classes within them.

The classes that I'm interested in all inherit from a PluginBase class but the below code doesn't seem to be registering them. Can anyone help?

        var assemblies = AppDomain.CurrentDomain.GetAssemblies();


        var builder = new ContainerBuilder();
        builder.RegisterAssemblyTypes(assemblies)
            .Where(t => t.BaseType == typeof(PluginBase))
            .AsImplementedInterfaces()
            .AsSelf();

        var container = builder.Build();
        var pluginClasses = container.Resolve<IEnumerable<PluginBase>>();

        //pluginClasses is empty!!!!
Nguyễn Văn Phong
  • 13,506
  • 17
  • 39
  • 56
Jon
  • 38,814
  • 81
  • 233
  • 382

3 Answers3

20

I think you need to specify the base class of your Plugins on registration. The call AsImplementedInterfaces registers the type with its implemented interfaces and not by its base type. You should update your registration to register your plugins as PluginBase.

Here´s the code:

var assemblies = AppDomain.CurrentDomain.GetAssemblies();


    var builder = new ContainerBuilder();
    builder.RegisterAssemblyTypes(assemblies)
        .Where(t => t.BaseType == typeof(PluginBase))
        .As<PluginBase>();

    var container = builder.Build();
    var pluginClasses = container.Resolve<IEnumerable<PluginBase>>();
Jehof
  • 34,674
  • 10
  • 123
  • 155
  • That works! Could I add the AsImplementedInterfaces for newer classes that do implement interfaces? – Jon Feb 06 '12 at 12:02
  • I think these two calls should work together. Then the type gets registered with by its base type and all interfaces it implements. – Jehof Feb 06 '12 at 12:05
  • Oops, just re-read what I wrote and doesn't make sense. If I have a class that inherits from PluginBase and has a constructor argument of an interface this won't work even with AsImplementedInterfaces. Do I do a new builder registration or can I amend the current code? – Jon Feb 06 '12 at 12:10
  • I just got it working by calling RegisterAssemblyTypes again. Thanks for your help. – Jon Feb 06 '12 at 12:27
  • 6
    Just a note, you don't need the `Where` call if you use `As`. – Nicholas Blumhardt Feb 06 '12 at 16:38
  • That does not works when assembly are not loaded. AppDomain.CurrentDomain.GetAssemblies is only returns loaded assemblies. – Omer Faruk Zorlu Sep 03 '18 at 11:40
7

Maybe do is this way:

builder
    .RegisterAssemblyTypes(AppDomain.CurrentDomain.GetAssemblies())
    .Where(t => t.GetInterfaces()
        .Any(i => i.IsAssignableFrom(typeof (IDependency))))
    .AsImplementedInterfaces()
    .InstancePerDependency();

In this code I use IDependency as a marker interface. You may replace it with your PluginBase class and remove Where method.

The point is to use IsAssignableFrom method.

Wojteq
  • 1,173
  • 9
  • 23
  • Will that allow for classes that don't implement interfaces and those that do? I'm working with legacy code so old stuff wont have interfaces but new stuff will – Jon Feb 06 '12 at 11:35
  • It should work with `Where(t => t.IsAssignableFrom(typeof(PluginBase))`. If not, I'll try to help you. – Wojteq Feb 06 '12 at 11:41
  • Of course remove `.AsImplementedInterfaces()`. I didn't notice this line. – Wojteq Feb 06 '12 at 11:52
  • That doesn't work either. PluginBase is abstract if that helps – Jon Feb 06 '12 at 11:55
  • If I put my original code back and just take out the where clause it works – Jon Feb 06 '12 at 11:58
  • Are the classes that extends `PluginBase` in your current AppDomain? – Wojteq Feb 06 '12 at 12:02
  • Yes they are. Jehof's seems to be getting somewhere but I still stuck – Jon Feb 06 '12 at 12:18
0

Pls, note that you shouldn't use AppDomain.CurrentDomain.GetAssemblies() due to an issue related to restarting IIS.

When hosting applications in IIS all assemblies are loaded into the AppDomain when the application first starts, but when the AppDomain is recycled by IIS the assemblies are then only loaded on demand.

To avoid this issue use the GetReferencedAssemblies() method on System.Web.Compilation.BuildManager to get a list of the referenced assemblies instead:

var assemblies = BuildManager.GetReferencedAssemblies().Cast<Assembly>();

That will force the referenced assemblies to be loaded into the AppDomain immediately making them available for module scanning.

For more detail, you can read here: https://autofac.readthedocs.io/en/latest/faq/iis-restart.html

Nguyễn Văn Phong
  • 13,506
  • 17
  • 39
  • 56