Registering Modules Autofac

Viewed 2421

I am using .NetCore 2.1 with autofaq in an asp.net core web application, my problem is the load method of my service module is not firing, I am instantiating a new instance of it as a parameter to registermodule, and the constructor of my service module is firing, this is a pretty typical setup, is there something i am doing wrong that anyone here can see?

ServiceModule.cs

namespace MyApp.Managers.DependencyManagement
{
    public class ServiceModule : Module
    {
        public ServiceModule()
        {
            Console.WriteLine("YES THIS LINE OF CODE IS FIRING?");
        }

        protected override void Load(ContainerBuilder builder)
        {
            Console.WriteLine("Why am i not firing? :-( ");
            builder.RegisterType<ItemManager>().As<IItemManager>().InstancePerLifetimeScope();
        }
    }
}

Program.cs (pretty basic void main here)

namespace MyApi.Api
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var host = new WebHostBuilder()
                .UseKestrel()
                .ConfigureServices(services => services.AddAutofac())
                .ConfigureAppConfiguration((context, options) =>
                {
                    options.SetBasePath(Directory.GetCurrentDirectory())
                    .AddCommandLine(args);
                })
                .UseContentRoot(Directory.GetCurrentDirectory())
                .UseIISIntegration()
                .UseStartup<Startup>()
                .Build();

            host.Run();
        }
    }
}

Startup.cs (lots of stuff going on here)

namespace MyApi.Api
{
    public class Startup
    {
        private readonly IHostingEnvironment env;
        private readonly IConfiguration config;
        private readonly ILoggerFactory loggerFactory;

        public Startup(
            IHostingEnvironment env,
            IConfiguration config,
            ILoggerFactory loggerFactory)
        {
            this.env = env;
            this.config = config;
            this.loggerFactory = loggerFactory;

            var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", EnvironmentVariableTarget.Machine);
            var appParentDirectory = new DirectoryInfo(this.env.ContentRootPath).Parent.FullName;

            var environmentName = environment ?? "Dev";
            var builder = new ConfigurationBuilder()
                .SetBasePath(env.ContentRootPath)
                .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
                .AddJsonFile($"appsettings.{environmentName}.json", optional: false, reloadOnChange: true)
                .AddEnvironmentVariables();
            this.Configuration = builder.Build();
        }

        public IConfigurationRoot Configuration { get; private set; }

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new Info { Title = "Item Service", Version = "v1" });
                c.DescribeAllEnumsAsStrings();
            });

            services
                .AddMvc()
                .SetCompatibilityVersion(Microsoft.AspNetCore.Mvc.CompatibilityVersion.Version_2_1)
                .AddFluentValidation(x => x.RegisterValidatorsFromAssembly(Assembly.GetExecutingAssembly()));

            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
        }

        public void ConfigureContainer(ContainerBuilder builder)
        {
            var connectionString = this.Configuration.GetConnectionString("GildedRose");
            ServiceConfiguration.Register(this.AddWebServices, connectionString);
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseHsts();
            }

            app.UseHttpsRedirection();

            app.UseSwagger();

            app.UseSwaggerUI(c =>
            {
                c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
            });

            app.UseMvc();
        }

        private void AddWebServices(ContainerBuilder builder)
        {
        }
    }
}

ServiceConfiguration.cs (the constructor is firing, but the load method never fires)

namespace MyApi.Api
{
    public class ServiceConfiguration
    {
        public static ContainerBuilder Register(Action<ContainerBuilder> additionalRegistration, string connectionString)
        {
            var containerBuilder = new ContainerBuilder();
            containerBuilder.RegisterType<ConfigurationStore>().As<IConfigurationStore>().InstancePerLifetimeScope();
            containerBuilder.RegisterType<Context>().AsSelf().InstancePerLifetimeScope();
            containerBuilder.RegisterModule(new StoreModule()
            {
                ConnectionString = connectionString,
            });
            containerBuilder.RegisterModule(new Managers.DependencyManagement.ServiceModule());
            additionalRegistration(containerBuilder);

            return containerBuilder;
        }
    }
}
2 Answers

You are not using the ContainerBuilder passed to the ConfigureContainer() method, instead you are instantiating and using a new one in the ServiceConfiguration.Register(), but that is not the one wired in the ASP.NET Core framework and also won't be built by it. That is why the Load() is not firing, you should use the one which is used by the framework.

Try to pass it to your static method like this:

ServiceConfiguration.Register(this.AddWebServices, connectionString, builder);

And use it in your method like:

public static ContainerBuilder Register(Action<ContainerBuilder> additionalRegistration, 
string connectionString, 
ContainerBuilder containerBuilder)
{
    containerBuilder.RegisterType<ConfigurationStore>()
    .As<IConfigurationStore>()
    .InstancePerLifetimeScope();
    // the rest
}

With autofac you've got a couple ways of starting a service on creation:

Implementing IStartable on your service and adding a Start() method

or something like this:

var builder = new ContainerBuilder();
builder.RegisterBuildCallback(c => c.Resolve<DbContext>());

// The callback will run after the container is built
// but before it's returned.
var container = builder.Build();
Related