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();
}
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