Reputation: 11750
I have a command-line application (similar to what would be created with the dotnet new worker
command) that hosts a BackgroundService
implementation, like this:
var host = Host.CreateDefaultBuilder(args)
.ConfigureServices(services => {
services.AddHostedService<MyBackgroundService>();
services.AddSingleton<IMyType>(myinstance);
// and so on...
}).Build();
await host.RunAsync();
Now, I would like this application to also host a web api. Currently, I have a whole separate builder that I'm instantiating inside the MyBackgroundService
class, with a separate set of services/singletons/whatever:
var builder = WebApplication.CreateBuilder();
// ... various web stuff...
var webApi = builder.Build();
// ... more web api stuff...
await webApi.StartAsync(cancellationToken);
I'd like to set this up to share a single DI container... how do I do that? My web api uses a WebApplicationBuilder
, while my BackgroundService
uses a DefaultBuilder
(which is a IHostBuilder
). Is there any way to set this up elegantly?
Edit: I found this: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/host/generic-host?view=aspnetcore-6.0 which gives me the ConfigureWebHostDefaults
method for the generic host, but the example isn't complete. I can put the AddControllers()
and AddRouting()
etc on the generic host, but once I call Build()
I can't do things like UseHttpLogging()
or UseSwagger()
or MapControllers()
.
Upvotes: 6
Views: 3209
Reputation: 606
Assuming you're starting from a console app and want to add in the API portion, you can do something like:
await Host.CreateDefaultBuilder(args)
.ConfigureServices(services =>
{
services.AddHostedService<SomeBackgroundService>();
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder
.ConfigureServices(services =>
{
services.AddControllers();
services.AddEndpointsApiExplorer();
services.AddSwaggerGen();
})
.Configure((hostContext, app) =>
{
if (hostContext.HostingEnvironment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
});
//can optionally use a startup file similar to what older versions of .NET used
//webBuilder.UseStartup<Startup>();
})
.Build()
.RunAsync();
}
Also, assuming you started from a console app, you may need to add:
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
to your csproj, as that will pull in the additional web options.
Edit: It appears the services specific to the web context need to be registered within the webBuilder.
Upvotes: 7