Configure AutoFac in ASP.NET Core 3.0 Preview 5 or higher
IvanFarkas opened this issue · 3 comments
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)
Runtime Error
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();
}
You didn't finish following the docs. Notice how you're registering things and building the container... but not attaching the container to the actual Microsoft DI system. The point of returning a new AutofacServiceProvider is to connect Autofac to Microsoft DI. That's not happening.
In ASP.NET Core 3.0 Preview 3 the following worked
public IServiceProvider ConfigureServices(IServiceCollection services)
{
. . .
// Creating the IServiceProvider out of the Autofac container. Valid in ASP.NET Core 3.0 Preview 3
// Not OK in ASP.NET Core 3.0 Preview 5, since "ConfigureServices returning an System.IServiceProvider isn't supported"
return new AutofacServiceProvider(ApplicationContainer);
}
In ASP.NET Core 3.0 Preview 5 there is a runtime error
System.NotSupportedException
HResult=0x80131515
Message=ConfigureServices returning an System.IServiceProvider isn't supported.
Source=Microsoft.AspNetCore.Hosting
StackTrace:
at Microsoft.AspNetCore.Hosting.Internal.GenericWebHostBuilder.UseStartup(Type startupType, HostBuilderContext context, IServiceCollection services)
at Microsoft.AspNetCore.Hosting.Internal.GenericWebHostBuilder.<>c__DisplayClass12_0.<UseStartup>b__0(HostBuilderContext context, IServiceCollection services)
at Microsoft.Extensions.Hosting.HostBuilder.CreateServiceProvider()
at Microsoft.Extensions.Hosting.HostBuilder.Build()
at FR.API.Program.Main(String[] args) in C:\Projects\FirstResponse\FR.API\Program.cs:line 13
I am reopening this since a solution was NOT provided by @tillig
Solution is in the docs. Notice one way to integrate returns void, not IServiceProvider. "Quick Start (With ConfigureContainer)" Important but subtle difference. If you still can't figure it out, hit StackOverflow up - this isn't a bug, it's a "how do I..." question that is already documented.