Configure Autofac DI container in ASP.NET CORE 3.1 Web API and consumer service from controller

3.7k views Asked by At

I need to configure Autofac DI container in ASP.NET CORE 3.1 Web API application and call register class from the container in Web API controller. I install Autofac.Extensions.DependencyInjection (6.0.0) and try to register container in my Startup.cs class but I am not able to use service. Also, do I need to configure the container in ConfigureServices(IServiceCollection services) class? The debugger does not hit IoCConfigurator() class after hitting point builder.RegisterModule(new IoCConfigurator());

Program.cs

 public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .UseServiceProviderFactory(new AutofacServiceProviderFactory())
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

Startup.cs

 public class Startup
{
    public IConfiguration Configuration { get; }
    public ContainerBuilder containerBuilder { get; }

    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
        containerBuilder = new ContainerBuilder();
    }

    public void ConfigureServices(IServiceCollection services)
    {
        ServicesConfigurator.Configure(services, Configuration);
        ConfigureIoC(services, containerBuilder);
    }

    public void ConfigureIoC(IServiceCollection services, ContainerBuilder builder)
    {

        builder.RegisterModule(new IoCConfigurator());
    }

IoCConfigurator.cs

 public class IoCConfigurator: Module
{
    protected override void Load(ContainerBuilder builder)
    {
        builder.RegisterType<NotifyService>().As<INotificationService>();
        builder.RegisterType<UsersService>().AsSelf();
    }
 }

INotification Interface & Class

 public interface INotificationService
{
   void notifyUsernameChanged(Users users);
}

   public class NotifyService : INotificationService
{
    public void notifyUsernameChanged(Users users)
    {
        string changedUsername = users.Username;

        Console.WriteLine("Username has changed to ... ");
        Console.WriteLine(changedUsername);
    }
}

User & User Service Class

 public class Users
{
    public string Username { get; set; }

    public Users(string username)
    {
        this.Username = username;
    }  
}

public class UsersService
{
    private INotificationService _notificationService;
    public UsersService(INotificationService notificationService)
    {
        this._notificationService = notificationService;
    }

    public void ChangeUsername(Users users, string newUsername)
    {
        users.Username = newUsername;
        _notificationService.notifyUsernameChanged(users);
    }
}

API Controller where I want to class the UserService Class and get reference from DI container

[Authorize]
[Route("txn/v1/[controller]/[action]")]
[ApiController]
public class DashboardController : ControllerBase
{

  [HttpPost("{name}")]
    public ActionResult<HelloMessage> GetMessage(string name)
    {
        // call container here...
        var result = new HelloMessage()
        {
            GivenName = name,
            ReturnMessage = "Dashboard@ Hello, Welcome to Texanite Digital"
        };

        return result;
    }
2

There are 2 answers

1
Jester On BEST ANSWER

Here is how I set it up. From command line:

md autof
cd autof
dotnet new webapi
dotnet add package Autofac.Extensions.DependencyInjection

Then edit using VS or VSCode. Program.cs - as you had it:

public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .UseServiceProviderFactory(new AutofacServiceProviderFactory())
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });

Next in Startup.cs, forget about ConfigureIoC, just register the services you want/need:

public void ConfigureContainer(ContainerBuilder builder)
    {
        // Register your own things directly with Autofac, like:
        //builder.RegisterModule();
        builder.RegisterType<NotifyService>().As<INotificationService>();
    }

Then in DashboardController.cs you need to "inject" the needed services from the constructor:

public class HelloMessage {
    public string GivenName { get; set; }
    public string ReturnMessage { get; set; }
}

//[Authorize]   Easier without Auth - don't need
[Route("[controller]")]
[ApiController]
public class DashboardController : ControllerBase
{
    private readonly INotificationService _notifyService;

    public DashboardController(INotificationService notifyService)
    {
        _notifyService = notifyService;
    }

    //[HttpPost("{name}")] - easier to test Get
    [HttpGet("{name}")]
    public ActionResult<HelloMessage> GetMessage(string name)
    {
        // call container here...
        _notifyService.notifyUsernameChanged(new Users(name));

        var result = new HelloMessage()
        {
            GivenName = name,
            ReturnMessage = $"Dashboard {name}, Welcome to Texanite Digital"
        };

        return result;
    }
}

My Results: Browser snip

With console output: console output with toxic name Your UserService was a little "out of the loop" but you can add an Interface for it and register with container and add it to injected services of the controller(s).

I could zip the whole thing up, just don't know where to put it or send it...

0
ZootHii On

Change your code like, that is all I think

Program.cs

public static void Main(string[] args)
{
    CreateHostBuilder(args).Build().Run();
}

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .UseServiceProviderFactory(new AutofacServiceProviderFactory())
        .ConfigureContainer<ContainerBuilder>(builder =>
        {
            builder.RegisterModule(new IoCConfigurator());
        })
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseStartup<Startup>();
        });
}

Startup.cs

public class Startup
{
public IConfiguration Configuration { get; }
public ContainerBuilder containerBuilder { get; }

public Startup(IConfiguration configuration)
{
    Configuration = configuration;
    containerBuilder = new ContainerBuilder();
}

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();
}