Use Autofac IoC Container in ASP.NET Core 6.0

Posted on March 16, 2023
.NET CoreautofaciocDependency injectionAutofac IoC containerInversion of Control (IoC)Configuration of services

.Net Core also gives you a built-in dependency injection framework. It provides enough functionality, but there are certain disadvantages like resolving a service, lazy instantiation, etc.

Autofac is an addictive IoC container .NET. It manages the dependencies between classes so that applications stay easy to change as they grow in size and complexity. This is achieved by treating regular .NET classes as components.

What issue are we resolving? Let's see the sample code.

This code defines a RepositoryManager class that implements the IRepositoryManager interface. The RepositoryManager class has two private Lazy fields for IPingPongRepository and IUnitOfWork, respectively. The Lazy type allows for deferred initialization of the fields until they are actually accessed for the first time.

We already talked about Lazy initialization in another article Part 2 - Onion Architecture/Clean Architecture in aspnet Core

Lazy Initialization

Did you see any issue with this code? Let's deep dive.

The problem with this code is that it tightly couples the RepositoryManager class with the concrete implementation of the PingPongRepository and UnitOfWork classes. This violates the principles of dependency inversion and makes it difficult to swap out the implementations of these classes with other implementations or mock objects during testing.

How to fix the problem above and leverage Lazy initialization by IOC implementation?

I'm trying to fix my own problem. Cheers!

The simple answer is using By using Autofac to manage the dependencies of the RepositoryManager class, we can take advantage of Autofac's powerful dependency injection capabilities, such as constructor injection, property injection, and more. This can make it easier to manage the dependencies of our application and promote more modular, testable code.

We already talked about Lazy initialization in another article Part 2 - Onion Architecture/Clean Architecture in aspnet Core

Configuring Autofac in .NET Core application

NuGet

PM> Install-Package Autofac
PM> Install-Package Autofac.Extensions.DependencyInjection

Add Autofac Modules i.e. PersistanceAutofacModule & PresentationAutofacModule

using Autofac;
using OnionDemo.Domain.Repositories;
using OnionDemo.Persistance.Repositories;

namespace OnionDemo.Presentation
{
    public class PersistanceAutofacModule : Module
    {
        protected override void Load(ContainerBuilder builder)
        {
            builder.RegisterType<RepositoryManager>().As<IRepositoryManager>();
            builder.RegisterType<UnitOfWork>().As<IUnitOfWork>();
            builder.RegisterType<PingPongRepository>().As<IPingPongRepository>();

            //builder.Services.AddScoped<IRepositoryManager, RepositoryManager>();

            // Other Lifetime
            // Transient
            //builder.RegisterType<PingPongRepository>().As<IPingPongRepository>()
            //    .InstancePerDependency();

            //// Scoped
            //builder.RegisterType<PingPongRepository>().As<IPingPongRepository>()
            //    .InstancePerLifetimeScope();

            //builder.RegisterType<PingPongRepository>().As<IPingPongRepository>()
            //    .InstancePerRequest();

            //// Singleton
            //builder.RegisterType<PingPongRepository>().As<IPingPongRepository>()
            //    .SingleInstance();

            // Scan an assembly for components
            //builder.RegisterAssemblyTypes(typeof(AssemblyReference).Assembly)
            //       .Where(t => t.Name.EndsWith("Repository"))
            //       .AsImplementedInterfaces();
        }
    }
}
using Autofac;
using OnionDemo.Domain.Repositories;
using OnionDemo.Persistance.Repositories;

namespace OnionDemo.Presentation
{
    public class PersistanceAutofacModule : Module
    {
        protected override void Load(ContainerBuilder builder)
        {
            builder.RegisterType<RepositoryManager>().As<IRepositoryManager>();
            builder.RegisterType<UnitOfWork>().As<IUnitOfWork>();
            builder.RegisterType<PingPongRepository>().As<IPingPongRepository>();

            //builder.Services.AddScoped<IRepositoryManager, RepositoryManager>();

            // Other Lifetime
            // Transient
            //builder.RegisterType<PingPongRepository>().As<IPingPongRepository>()
            //    .InstancePerDependency();

            //// Scoped
            //builder.RegisterType<PingPongRepository>().As<IPingPongRepository>()
            //    .InstancePerLifetimeScope();

            //builder.RegisterType<PingPongRepository>().As<IPingPongRepository>()
            //    .InstancePerRequest();

            //// Singleton
            //builder.RegisterType<PingPongRepository>().As<IPingPongRepository>()
            //    .SingleInstance();

            // Scan an assembly for components
            //builder.RegisterAssemblyTypes(typeof(AssemblyReference).Assembly)
            //       .Where(t => t.Name.EndsWith("Repository"))
            //       .AsImplementedInterfaces();
        }
    }
}

ASP.Net Core 6.0 Configuration (Program.cs)

builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());

// Call ConfigureContainer on the Host sub property 
builder.Host.ConfigureContainer<ContainerBuilder>(builder =>
{
    builder.RegisterModule(new PersistanceAutofacModule());
    builder.RegisterModule(new PresentationAutofacModule());
});

Let's compare the new implementation of RepositoryManager.cs

namespace OnionDemo.Persistance.Repositories
{
    public sealed class RepositoryManager : IRepositoryManager
    {
        private readonly IPingPongRepository _pingPongRepository;
        private readonly IUnitOfWork _unitOfWork;

        public RepositoryManager(IPingPongRepository pingPongRepository, IUnitOfWork unitOfWork)
        {
            _pingPongRepository = pingPongRepository;
            _unitOfWork = unitOfWork;
        }

        public IPingPongRepository PingPongRepository => _pingPongRepository;

        public IUnitOfWork UnitOfWork => _unitOfWork;
    }
}

Here is the full sample code to download from Github

Here is recent commit change

Git History

What are the benefit of Autofac and the new way of code?

The main benefit of this implementation is that it promotes dependency injection and adheres to the SOLID principles, particularly the Dependency Inversion Principle (DIP) using Lazy initialization. By injecting the IPingPongRepository and IUnitOfWork dependencies into the RepositoryManager constructor, we can easily switch out the implementations of these dependencies at runtime without having to modify the RepositoryManager class itself.

This makes the code more modular, testable, and maintainable. For example, we could easily replace the IPingPongRepository implementation with a different implementation, such as a mock object for testing purposes, or a different implementation for a different database provider, without having to modify the RepositoryManager class.

Additionally, we can write more abstract code and less coupled it to specific implementation details by using interfaces instead of concrete types. This can make it easier to reason about and modify the code in the future.

Overall, this implementation promotes better software design practices and can lead to more maintainable and robust code.

Thanks for reading!


Posted on March 16, 2023

Anonymous User

April 16, 2024

thanks man, it was helpful

Anonymous User

October 9, 2023

thanks for sharing

Anonymous User

March 16, 2023

Great explanation

Profile Picture

Arun Yadav

Software Architect | Full Stack Web Developer | Cloud/Containers

Subscribe
to our Newsletter

Signup for our weekly newsletter to get the latest news, articles and update in your inbox.

More Related Articles