Search code examples
c#.netautofacautofac-moduleautofac-configuration

Skip unknown autofac modules configured in autofac.json


My application is initialized from autofac.json file:

{
    "defaultAssembly": "Application",
        "modules": [
            { "type": "Application.Plugin1.Module, Application.Plugin1" },
            { "type": "Application.Plugin2.Module, Application.Plugin2" },
            { "type": "Application.Plugin3.Module, Application.Plugin3" }
        ]
}

But every plugins are not mandatory.

When I run the application with a missing plugin, the following exception is thrown :

Unhandled Exception: System.InvalidOperationException: The type 'Application.Plugin2.Module, Application.Plugin2' could not be found. It may require assembly qualification, e.g. "MyType, MyAssembly".
   at Autofac.Configuration.Core.ConfigurationExtensions.GetType(IConfiguration configuration, String key, Assembly defaultAssembly)
   at Autofac.Configuration.Core.ModuleRegistrar.RegisterConfiguredModules(ContainerBuilder builder, IConfiguration configuration)
   at Autofac.Configuration.Core.ConfigurationRegistrar.RegisterConfiguration(ContainerBuilder builder, IConfiguration configuration)
   at Autofac.Module.Configure(IComponentRegistry componentRegistry)
   at Autofac.ContainerBuilder.Build(IComponentRegistry componentRegistry, Boolean excludeDefaultModules)
   at Autofac.ContainerBuilder.Build(ContainerBuildOptions options)

How can I ignore plugins that are not present in the application folder?


Solution

  • This is the default behavior of the Autofac.Configuration.ConfigurationModule.

    You can change the way the configured module are load by implementing a custom IModuleRegistrar

    We can easily modify the default ModuleRegistrar implementation to add optional module.

    // based on https://github.com/autofac/Autofac.Configuration/blob/0f84f3569eb5a59013859f6eaa9b1ea4cf8e77a1/src/Autofac.Configuration/Core/ModuleRegistrar.cs
    public class OptionalModuleRegistrar : IModuleRegistrar
    {
        public virtual void RegisterConfiguredModules(ContainerBuilder builder, IConfiguration configuration)
        {
            if (builder == null)
            {
                throw new ArgumentNullException(nameof(builder));
            }
    
            if (configuration == null)
            {
                throw new ArgumentNullException(nameof(configuration));
            }
    
            var defaultAssembly = configuration.DefaultAssembly();
            foreach (var moduleElement in configuration.GetSection("modules").GetChildren())
            {
                var moduleTypeName = moduleElement["type"];
                var moduleType = GetType(moduleTypeName, defaultAssembly);
                if (moduleType == null)
                {
                    // Log moduleTypeName
                    Console.WriteLine($"{moduleTypeName} module not found");
                    continue;
                }
    
                var module = (IModule)null;
                using (var moduleActivator = new ReflectionActivator(
                    moduleType,
                    new DefaultConstructorFinder(),
                    new MostParametersConstructorSelector(),
                    moduleElement.GetParameters("parameters"),
                    moduleElement.GetProperties("properties")))
                {
                    module = (IModule)moduleActivator.ActivateInstance(new ContainerBuilder().Build(), Enumerable.Empty<Parameter>());
                }
    
                builder.RegisterModule(module);
            }
        }
    
        private Type GetType(String moduleTypeName, Assembly defaultAssembly)
        {
            var moduleType = Type.GetType(moduleTypeName);
            if (moduleType == null && defaultAssembly != null)
            {
                moduleType = defaultAssembly.GetType(moduleTypeName, false, true);
            }
    
            return moduleType;
        }
    }
    

    and you can use it like this :

    // Add the configuration to the ConfigurationBuilder.
    var config = new ConfigurationBuilder();
    config.AddJsonFile("autofac.json");
    
    // Register the ConfigurationModule with Autofac.
    var module = new ConfigurationModule(config.Build());
    module.ConfigurationRegistrar = new ConfigurationRegistrar(
        new ComponentRegistrar(), 
        new OptionalModuleRegistrar());
    var builder = new ContainerBuilder();
    builder.RegisterModule(module);
    
    // build the Autofac container
    var container = builder.Build();