Search code examples
c#asp.net-core.net-core-service-worker

ASP.NET Core in a Worker Service doesn't call Configure IApplicationBuilder


I was migrating an ASP.NET Core App to the Worker Service template and was intending to keep the Startup code. However after

within Program I kept the CreateHostBuilder as described on the MS Docs:

public static void Main(string[] args)
{
    CreateHostBuilder(args).Build().Run();
}

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .UseWindowsService()
        .ConfigureWebHostDefaults(
            webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            })
        .ConfigureServices(
            services =>
            {
                services.AddHostedService<Worker>();
            });

while debugging, the ConfigureServices is being called

public void ConfigureServices(IServiceCollection services)

but the Configure within the Startup, is not reached / called

public void Configure(IApplicationBuilder app)

before it crashes calling Run().

I also tried this with the same result:

public static IHostBuilder CreateHostBuilder(string[] args)
    => Host.CreateDefaultBuilder(args)
        .UseWindowsService()
        .ConfigureWebHostDefaults(webBuilder => webBuilder.Configure(Startup.Configure))
        .ConfigureServices(
            services =>
            {
                Startup.ConfigureServices(services);
                services.AddHostedService<Worker>();
            });

The interesseting part is that the following code actually calls the Startup.Configure(IApplicationBuilder app):

public static IHostBuilder CreateHostBuilder(string[] args)
    => Host.CreateDefaultBuilder(args)
        .UseWindowsService()
        .ConfigureWebHostDefaults(webBuilder => webBuilder.Configure(Startup.Configure));

As soon as I am adding ConfigureServices it skips the IApplicationBuilder configuration call.

Am I missing something or what is the suggested way to achieve this?

Edit:

the exact error is:

InvalidOperationException: Unable to resolve service for type 'Microsoft.AspNetCore.Builder.IApplicationBuilder' while attempting to activate 'Kledex.Extensions.KledexAppBuilder'.

stack trace:

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

the error happens as soon as it reaches CreateHostBuilder(args).Build().Run(); and tries to resolve the registered services, while the above one has a dependency to some config app.UseSomething(); within the Startup.Configure() method.

A breakpoint in Startup.Configure() doesn't get hit.


Solution

  • Given that you are trying to configure web host defaults and use ASP.NET Core features like IApplicationBuilder, I believe that you are planning to run the service over some kind of web server. Is this correct?

    If so, besides the other good suggestions, I have another one, which is to keep using an ASP.NET Core app - obviously enabling the usage of the Startup almost as is (with ConfigureServices and Configure methods) and perhaps most of your previous app.

    To do so, in your Worker csproj, you could replace <Project Sdk="Microsoft.NET.Sdk.Worker"> by <Project Sdk="Microsoft.NET.Sdk.Web">.

    Then, you can configure your CreateHostBuilder such as:

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(
                webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
    }
    

    Please note that I removed UseWindowsService() on purpose, since I am describing a case of using Worker services and not specifically Windows services.

    Now you can keep using your Startup class, adding the registration of your background service(s):

    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            // ...
        }
        
        public void ConfigureServices(IServiceCollection services)
        {
            // ...
            services.AddHostedService<Worker>();
        }
    
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            // ...
        }
    }
    

    Hope this helps :) However, if you specifically want to develop Windows services rather than Worker services, please let us know.

    In this case, we keep having an ASP.NET Core WebApp/WebAPI with all its capabilities. We just added background services to it :)