Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Configure AutoFac in ASP.NET Core 3.0 Preview 5 or higher

Following the AutoFac documentation, I was able to use AutoFac in ASP.NET Core 3.0 Preview 3. ASP.NET Core 3.0 Preview 4 and ASP.NET Core 3.0 Preview 5 introduced breaking changes and AutoFac no longer works. My controller methods return runtime errors.

The differences between ASP.NET Core 3.0 Preview 3 and ASP.NET Core 3.0 Preview 5 in my code is as follows:

IWebHostBuilder -> IHostBuilder

CreateWebHostBuilder -> CreateHostBuilder

WebHost.CreateDefaultBuilder(args) -> Host.CreateDefaultBuilder(args)

public IServiceProvider ConfigureServices(IServiceCollection services)

to

public void ConfigureServices(IServiceCollection services)
System.AggregateException
  HResult=0x80131500
  Message=Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType: API.Controllers.CityController Lifetime: Transient ImplementationType: CityController': Unable to resolve service for type 'IUnitOfWork' while attempting to activate 'CityController'.) (Error while validating the service descriptor 'ServiceType: LocationController Lifetime: Transient ImplementationType: LocationController': Unable to resolve service for type 'IUnitOfWork' while attempting to activate 'LocationController'.) (Error while validating the service descriptor 'ServiceType: PersonController Lifetime: Transient ImplementationType: PersonController': Unable to resolve service for type 'IUnitOfWork' while attempting to activate 'PersonController'.) (Error while validating the service descriptor 'ServiceType: SchoolController Lifetime: Transient ImplementationType: SchoolController': Unable to resolve service for type 'IUnitOfWork' while attempting to activate 'SchoolController'.) (Error while validating the service descriptor 'ServiceType: TestParentController Lifetime: Transient ImplementationType: TestParentController': Unable to resolve service for type 'IUnitOfWork' while attempting to activate 'TestParentController'.) (Error while validating the service descriptor 'ServiceType: TypeController Lifetime: Transient ImplementationType: TypeController': Unable to resolve service for type 'IUnitOfWork' while attempting to activate 'TypeController'.)
  Source=Microsoft.Extensions.DependencyInjection
  StackTrace:
   at Microsoft.Extensions.DependencyInjection.ServiceProvider..ctor(IEnumerable`1 serviceDescriptors, ServiceProviderOptions options)
   at Microsoft.Extensions.DependencyInjection.ServiceCollectionContainerBuilderExtensions.BuildServiceProvider(IServiceCollection services, ServiceProviderOptions options)
   at Microsoft.Extensions.DependencyInjection.DefaultServiceProviderFactory.CreateServiceProvider(IServiceCollection containerBuilder)
   at Microsoft.Extensions.Hosting.Internal.ServiceFactoryAdapter`1.CreateServiceProvider(Object containerBuilder)
   at Microsoft.Extensions.Hosting.HostBuilder.CreateServiceProvider()
   at Microsoft.Extensions.Hosting.HostBuilder.Build()
   at API.Program.Main(String[] args) in C:\Projects\FirstResponse\API\Program.cs:line 13

Inner Exception 1:
InvalidOperationException: Error while validating the service descriptor 'ServiceType: CityController Lifetime: Transient ImplementationType: CityController': Unable to resolve service for type 'IUnitOfWork' while attempting to activate 'CityController'.

Inner Exception 2:
InvalidOperationException: Unable to resolve service for type 'IUnitOfWork' while attempting to activate 'CityController'.

Program.cs

public static IHostBuilder CreateHostBuilder(string[] args) =>
  Host.CreateDefaultBuilder(args)
    .ConfigureWebHostDefaults(webBuilder =>
    {
      webBuilder
        .UseStartup<Startup>()
        .ConfigureLogging((hostingContext, builder) =>
        {
          builder.ClearProviders();
          builder.SetMinimumLevel(LogLevel.Trace);
          builder.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
          builder.AddConsole();
          builder.AddDebug();
        })
        .UseNLog();
    });

Startup.cs

public void ConfigureServices(IServiceCollection services)
{
  services
    .AddCustomOptions(Configuration)
    .AddCors()
    .AddJwtAuthentication()
    .AddHttpClients()
    .AddCustomMVC()
    .AddIIS()
    .AddCaching()
    .AddCustomDbContext(Configuration, Environment)
    .AddSwagger()
    .AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies())
    .AddHealthChecksUI();

  var serviceProvider = services.BuildServiceProvider();

  _appSettings = serviceProvider.GetService<IOptionsSnapshot<AppSettings>>().Value;

  var connectionString = Configuration.GetConnectionString(nameof(FirstResponseContext));

  // Create a Autofac container builder
  var builder = new ContainerBuilder();

  // Read service collection to Autofac
  builder.Populate(services);

  // Use and configure Autofac
  builder.RegisterModule(new MediatorModule());
  builder.RegisterModule(new ApplicationModule(connectionString));

  // build the Autofac container
  ApplicationContainer = builder.Build();

  // creating the IServiceProvider out of the Autofac container
  //return new AutofacServiceProvider(ApplicationContainer);
}

ApplicationModule.cs

protected override void Load(ContainerBuilder builder)
{
  builder.RegisterType<HttpContextAccessor>().As<IHttpContextAccessor>().SingleInstance();
  builder.RegisterType<ModelValidationAttribute>().InstancePerLifetimeScope();
  builder.RegisterType<ETagCache>().InstancePerLifetimeScope();

  builder.RegisterType<FirstResponseContext>().As<DbContext>().As<IUnitOfWork>().InstancePerLifetimeScope();
}
like image 477
JStein Avatar asked May 30 '19 20:05

JStein


People also ask

Should I use Autofac in .NET core?

Autofac is a . Net-based IoC container. When classes interact with one another, it manages the dependencies between them that allow applications to remain flexible as they grow in size and complexity. Autofac is the most widely used DI/IoC container for ASP.NET, and it is fully compatible with.NET Core as well.

Is Autofac A IoC?

Autofac is an IoC container for Microsoft . NET. It manages the dependencies between classes so that applications stay easy to change as they grow in size and complexity.

Is Autofac a framework?

AutoFac is an Inversion of Control container that resolves dependencies of an application. This means that it also is a dependency injection framework.


1 Answers

A few changes would need to be done to conform to the new syntax

You need to plug in the service provider factory for AutoFac

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
      .UseServiceProviderFactory(new AutofacServiceProviderFactory()) //<--NOTE THIS
      .ConfigureWebHostDefaults(webBuilder => {
          webBuilder         
            .UseStartup<Startup>()
            .ConfigureLogging((hostingContext, builder) => {
                builder.ClearProviders();
                builder.SetMinimumLevel(LogLevel.Trace);
                builder.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
                builder.AddConsole();
                builder.AddDebug();
            })
            .UseNLog();
    });

Then in the ConfigureContainer method of your Startup class, register things directly into an Autofac ContainerBuilder.

public IConfigurationRoot Configuration { get; private set; }

public void ConfigureServices(IServiceCollection services) {
    services
        .AddCustomOptions(Configuration)
        .AddCors()
        .AddJwtAuthentication()
        .AddHttpClients()
        .AddCustomMVC()
        .AddIIS()
        .AddCaching()
        .AddCustomDbContext(Configuration, Environment)
        .AddSwagger()
        .AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies())
        .AddHealthChecksUI();    
}

public void ConfigureContainer(ContainerBuilder builder) {
   var connectionString = Configuration.GetConnectionString(nameof(FirstResponseContext));

    // Use and configure Autofac
    builder.RegisterModule(new MediatorModule());
    builder.RegisterModule(new ApplicationModule(connectionString));
}

The IServiceProvider will automatically be created for you, so there’s nothing you have to do but register things.

Some of this was taken directly from Autofac documentation for Asp.Net Core

like image 95
Nkosi Avatar answered Sep 22 '22 10:09

Nkosi