Search code examples
exceptionautofacregistration

Autofac registrations present but servicelocator throws ComponentNotRegisteredException


Here is some sample code

public void RegisterDependencies()
        {
            var builder = new ContainerBuilder();

            ConfigureModules(builder);
            ConfigureProfiles(builder);

            var container = builder.Build();

            ServiceLocator.SetLocatorProvider(() => new AutofacServiceLocator(container));
        }

protected virtual void ConfigureModules(ContainerBuilder builder)
        {
            var assemblies = GetAssemblies();
            {
                builder.RegisterAssemblyModules(assemblies);
            }
        }

        protected virtual void ConfigureProfiles(ContainerBuilder builder)
        {
            var profiles = GetTypes<Profile>();

            builder.RegisterInstance(new MapperConfiguration(cfg => cfg.AddMaps(profiles)).CreateMapper())
                .As<IMapper>();
        }

The GetAssemblies() method loads and returns an array of assemblies referenced by the app. All the modules are registered and showing up in the servicelocator. However, when trying to resolve an interface using the following code, I get the ComponentNotRegisteredException:

_dlMembershipParserService =
                ServiceLocator.Current.GetInstance<IDLMembershipParserService>();

Here is a sample of one of the Modules:

public class ServiceModule : Autofac.Module
    {
        protected override void Load(ContainerBuilder builder)
        {
            builder.RegisterType<DLMembershipParserService>().As<IDLMembershipParserService>();
            builder.RegisterType<DLMembershipExporterService>().As<IDLMembershipExporterService>();
        }
    }

Does anyone have any ideas? The assemblies are loaded and there is only one assembly for each dll being loaded.

I've also tried the following code with the same result:

protected virtual void ConfigureModules(ContainerBuilder builder)
        {
            var modules = GetTypes<IModule>().Select(m => (IModule)Activator.CreateInstance(m));

            foreach (var module in modules)
            {
                builder.RegisterModule(module);
            }
        }

But the only thing that works is a had reference to the Module, like so:

builder.RegisterModule<ServiceModule>();

But this isn't what I want. I need to be able to add modules and have them discovered by the app.

I appreciate any insight into this.

Thanks


Solution

  • So I discovered what I need to do, from a .NET Core point of view, in order to discover and load assemblies dynamically from .NET Core.

    There is a nuget package required to Load .NET Core assemblies so that all the registered types can be resolved at runtime. The package is called System.Runtime.Loader.

    Once installed, I was able to successfully discover assemblies based on Type information, then load, register and resolve types at runtime.

    Here is some sample code:

    public override Type[] GetTypes<T>()
    {
        var assemblyPath = _assemblyHelper.GetEntryAssemblyLocation();
        var path = _pathHelper.GetDirectoryName(assemblyPath);
    
        var files = _fileHelper.GetFiles(path, "Tss.DLMembership.*.dll");
    
        return files.SelectMany(file => _assemblyHelper.LoadFile(file).GetTypes()
            .Where(t => typeof(T).IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract))
        .ToArray();
    }
    
    public class AssemblyHelper : IAssemblyHelper
    {
        public string GetEntryAssemblyLocation()
        {
            return AppContext.BaseDirectory;
        }
    
        public Assembly LoadFile(string fileName)
        {
            return AssemblyLoadContext.Default.LoadFromAssemblyPath(fileName);
        }
    }
    

    This solved my issue with resolving registered types after loading the assemblies and registering types.