'ConfigureServices returning an System.IServiceProvider isn't supported.' in .NET Core 3.1 using Autofac - asp.net-core

I want to use autofac injection instead of default .net core solution.
Here is my startup file :
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddMvc(option => option.EnableEndpointRouting = false) ;
var cb = new ContainerBuilder();
cb.RegisterModule<mydependecymodule>();
cb.Populate(services);
var container = cb.Build();
return new AutofacServiceProvider(container);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseDeveloperExceptionPage();
app.UseStatusCodePages();
app.UseStaticFiles();
app.UseMvc(routes=>routes.MapRoute("default","/{controller=home}/{action=index}"));
}
And here is my program.cs
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
}).UseServiceProviderFactory(new AutofacServiceProviderFactory());
But when I run my application I get this error in my main method:
System.NotSupportedException: 'ConfigureServices returning an System.IServiceProvider isn't supported.'

In ASP.NET Core 3.0 the ASP.NET Core hosting model changed and you can't return an IServiceProvider anymore. This is documented in the Autofac docs for integrating with ASP.NET Core 3.0+.
You have to switch your ConfigureServices to be void, and if you want to register stuff directly with Autofac you need to use ConfigureContainer. You also need to register the AutofacServiceProviderFactory in your Program.Main method when you construct the host. There are examples in the documentation showing how to do this.

Related

ASP.NET core start dependency injection at when app is started

I am injecting one of my services as last item in the ConfigureServices method:
services.AddSingleton<IBot>(_ => new De.Impl.Bot(Configuration));
I am running the app in docker container so whenever container is restarted I need to invoke my controller so I can get my service running. How can I get it running in the beginning of the configuration part?
As for .NET Core 3.1 and .NET 5.0
First, you can write your business code as an extension:
using Microsoft.Extensions.Hosting;
public static IHost DoSomething(this IHost host)
{
using (var scope = host.Services.CreateScope())
{
var services = scope.ServiceProvider;
var yourService = services.GetService<YourService>();
yourService.DoSomething();
}
return host;
}
So if you want to invoke that method every time your application starts, simply call:
// .NET 5.0 Style
public static void Main(string[] args)
{
CreateHostBuilder(args)
.Build()
.DoSomething()
.Run();
}
public static IHostBuilder CreateHostBuilder(string[] args)
{
return Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder => webBuilder.UseStartup<Startup>());
}
As for .NET 6.0
It's gonna be easier. Simply access var yourService = app.Services.GetRequiredService<YourService> in the Program.cs.
// .NET 6.0 style, in Program.cs, before app.Run();
var yourService = app.Services.GetRequiredService<YourService>();
yourService.DoSomething();
app.Run();

starup file changes in Asp.net core

I am Upgrading .Net core web api solution 2.2 to 3.1
I have question what should i use in statrup.cs file for 3.1
// currently i am using this
public Startup(Microsoft.AspNetCore.Hosting.IHostingEnvironment env)
public Startup(Microsoft.Extensions.Hosting.IHostingEnvironment env)
I am Upgrading .Net core web api solution 2.2 to 3.1 I have question what should i use in statrup.cs file for 3.1
If you create a new ASP.NET Core 3.1 API project using the API template, you would find it uses below Startup class.
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
Compare it with old one, you can find the following changes:
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2) is changed to services.AddControllers()
IHostingEnvironment is obsolete, and it uses IWebHostEnvironment now
app.UseEndpoints, endpoint routing is used

Register Service in ASP.NET Core as part of a middleware registration

Using ASP.NET Core 3.1 I am adding a SitemapMiddleware on Startup's Configure method:
public void Configure(IApplicationBuilder builder, IWebHostEnvironment environment) {
builder.UseSitemap();
}
Where the UseSitemap extension is:
public static class SitemapMiddlewareExtensions {
public static IApplicationBuilder UseSitemap(this IApplicationBuilder builder) {
return builder.MapWhen(x => x.Request.Path.StartsWithSegments("/sitemap.xml"),
x => x.UseMiddleware<SitemapMiddleware>(route));
}
}
But the middleware uses an ISitemapService which I need to register as:
services.AddScoped<ISitemapService, SitemapService>();
How can I do this inside the method UseSitemap?
Or maybe create an IServicesCollection extension to use in Startup's ConfigureServices that registers the SitemapService?

ConfigureContainer in .NET Core 3.1 Generic Host implementation

I am trying to migrate our framework project to .NET Core 3.1.
As part of the migration, I am trying to register modules via ConfigureContainer method provided by the GenericHost.
This is what I have:
Host.CreateDefaultBuilder(args)
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
.ConfigureContainer<ContainerBuilder>(builder => builder.RegisterModule(new
WorkerServiceDependencyResolver.WorkerServiceDependencyResolver()))
And my WorkerServiceDependencyResolver has the following:
builder.RegisterModule(new FirstModule());
builder.RegisterModule(new SecondModule());
But when I do it this way, my application doesn't run, it starts without any error, but doesn't do anything.
But If I write it this way (this is how we had in .NET Framework):
var builder = new ContainerBuilder();
builder.RegisterModule(new FirstModule());
builder.RegisterModule(new SecondModule());
_container = builder.Build();
Everything works as expected when I explicitly build the container, but my understanding was that we do not need that in .NET Core?
Any inputs are greatly appreciated.
Cheers!
By specifying to the IHostBuilder that the Service Provider Factory is an AutofacServiceProviderFactory, it allows you create to a method right inside your Startup class, called ConfigureContainer which takes the ContainerBuilder as a parameter.
This is how you would instantiate the IHostBuilder. Nothing fancy, just following the ASP NET Core guide.
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
Then, in the Startup class, add that method.
public class Startup
{
public Startup(IConfiguration configuration) => Configuration = configuration;
public IConfiguration Configuration { get; }
// ...
public void ConfigureContainer(ContainerBuilder builder)
{
// Here you register your dependencies
builder.RegisterModule<FirstModule>();
}
// ...
}
Then, your IContainer will be the IOC Container of your ASPNET Core application scope.
Notice than the builder is not being built at any time. This will be done by the IHostBuilder at some point (making use of the Autofac extension).
Hope that helps.

Hosting Web API in .Net Core Worker Service - cannot reference IWebHostEnvironment

I'm creating a .NET Core Worker Service, and want to expose ASP.Net Core Web APIs for the service. I'm using .NET Core 3.0.
Initially, my plan was to replace IHostBuilder with IWebHostBuilder and add a Startup class just like a regular Asp.Net Core web app (this is probably an oversimplification, though).
My plan was to simply try to replace
public static IHostBuilder CreateHostBuilder(string[] args)
{
return Host.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) =>
{
services.AddHostedService<Worker>();
});
}
with
public static IWebHostBuilder CreateHostBuilder(string[] args)
{
return WebHost.CreateDefaultBuilder(args)
.ConfigureServices(services =>
{
services.AddHostedService<Worker>();
}).UseStartup<Startup>();
}
which may not work at all, but at least it's a starting point...
What's blocking me from trying this approach is that I cannot implement my Startup class because IWebHostEnvironment is unavailable.
Here's my
<PropertyGroup>
<TargetFramework>netcoreapp3.0</TargetFramework>
<UserSecretsId>dotnet-WorkerServices-0E977A2C-F0C8-49E7-B00A-5EB01B99FBEB</UserSecretsId>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Hosting.Server.Abstractions" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="3.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="3.0.0" />
</ItemGroup>
As far as I know, IWebHostEnvironment should be in the Microsoft.Extensions.Hosting.Abstractions nuget package, but referencing it does not seem to work.
Does anyone have any ideas?
-Thanks!
It is much easier to add a service to an API project. That's just one extra line.
If you can't or don't want to start over, change your project manually. Forget about IWebHostBuilder, it is now obsolete or deprecated or something.
I could post some fragments here but much easier: create a temporary API project, copy over the Program and Startup classes (but keep your namespaces) and then, inside Startup:
public void ConfigureServices(IServiceCollection services)
{
services.AddHostedService<Worker>(); // the worker will run
services.AddControllers();
}
I researched a lot and I did this issue using some new methods which were not well-formed and lack performance, and I tried to find a correct way of doing this problem, finally, I solved it and I've shared my experiences in this post. You can use the following steps which are working 100%, and also, you can clone the Worker-Service Web-API template from my GitHub profile.
Actually, you needn't use IWebHostBuilder. The following steps are enough to self-host a WebAPI in a .net core worker service and host worker service in windows services:
Create a simple console application.
Install packages "Microsoft.AspNetCore.App" and "Microsoft.Extensions.Hosting.WindowsServices" using NuGet in your console application.
Create an empty file named Worker.cs and put the following code inside it:
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace WorkerServiceWebAppTemplate
{
public class Worker : BackgroundService
{
private readonly ILogger<Worker> _logger;
public Worker(ILogger<Worker> logger)
{
_logger = logger;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
_logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
await Task.Delay(1000, stoppingToken);
}
}
}
}
The above class is your worker service main file which is inherited from BackgroundService, personally, I inherit IHostedService most of the time.
Create another file named Startup.cs and put the following lines of codes:
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Hosting;
namespace WorkerServiceWebAppTemplate
{
public class Startup
{
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
app.UseDeveloperExceptionPage();
else
app.UseHsts();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/", async context =>
{
await context.Response.WriteAsync("Hello World!");
});
});
}
}
}
The Startup file is your web server file and it starts a host and has a simple GET API (/) returns a simple message, you can extend it.
Finally, you've to start your worker service and your host at the same time. change your Program.cs like the following codes:
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace WorkerServiceWebAppTemplate
{
class Program
{
static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
private static IHostBuilder CreateHostBuilder(string[] args)
{
return Host.CreateDefaultBuilder(args)
.UseWindowsService()
.ConfigureServices((hostBuilderContext, services) =>
{
services.AddHostedService<Worker>();
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}
}
The following lines in your Program.cs file do the magic:
.UseWindowsService()
.ConfigureServices((hostBuilderContext, services) =>
{
services.AddHostedService<Worker>();
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});