Background Worker Services in .NET 8

Background Worker Services in .NET 8


   You could get a starting point in Visual Studio by doing the "Worker Service" template by File > New > Project > "Worker Service", but it fails to: 1) create an actual Windows service (but rather is cloud focused), 2) fails to have a dropdown of types of services (such as background service, cloud-service, queue service, signal completion service, timer service, and windows service), and 3) does not have a "scoped services" checkbox like it should. I am thinking that the "scoped services" might be a checkbox because I could see that apply to multiple times of services.  The code generated could just match the examples of the types services found at: https://github.com/dotnet/samples/tree/main/core/workers  .



Remember that you need to:
   1) start Services in administrator mode.
   2) right-click in Services to Start.
   3) stop the Service if compiling a new version if service points to the bin directory location.
   4) you must refresh to see any changes on the Services screen.

A couple points about Program.cs:

   1) CreateDefaultBuilder is good starting point for a service, rather than the heavier CreateApplicationBuilder.  The "Worker Service" template begins with CreateApplicationBuilder because it is probably thinking you are going to use in Docker or other hosted container.

   2) For all services, the UseWindowsService is critical if this is to run as a service in Windows. This requires Nuget package of Microsoft.Extensions.Hosting, but no USING commands.

   3) For all services, adding the worker as a hosted service is good.


Program.cs (with no logging) (bolded are critical)

    [ExcludeFromCodeCoverage]
    public static class Program
    {
        public static void Main(string[] args)
        {
            try
            {
                Environment.CurrentDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!;
                var builder = Host.CreateDefaultBuilder(args);
                builder.UseWindowsService(options => options.ServiceName = "XXXXXXXXXX")
                .ConfigureAppConfiguration((hostContext, configBuilder) => configBuilder
                    .SetBasePath(Directory.GetCurrentDirectory())
                    .AddJsonFile("appsettings.json", optional: false, reloadOnChange: false)
                    .AddJsonFile($"appsettings.{hostContext.HostingEnvironment.EnvironmentName}.json", optional: true, reloadOnChange: true)
                    .AddJsonFile($"appsettings.{Environment.MachineName}.json", true, true)
                    .Build())
                .ConfigureServices(services =>
                {
                    services.AddHostedService<ScopedBackgroundWorker>();
                    services.AddSingleton<IContextFactory, ContextFactory>();
                    services.AddDependencies();
                });

                IHost host = builder.Build();
                host.Run();
            }
        }
    }


DependencyConfiguration.cs

        /// <summary> Registering all API dependencies. 
        ///           Order created in matters here. Do dependencies of later objects first. </summary>    
    [ExcludeFromCodeCoverage]
    public static class DependencyConfiguration
    {
        public static IServiceCollection AddDependencies(this IServiceCollection services)
        {           
            services.AddScoped<IContextFactory, ContextFactory>();
            // etc. of AddScoped for each interface and object
            return services;
        }        
    }

Worker.cs

    [ExcludeFromCodeCoverage]
    public class xxxBackgroundWorker : BackgroundService
    {
        private readonly IxxxService _xxxService;

        public xxxBackgroundWorker(IxxxService xxxService)
        {
            _xxxService = xxxService;
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                await _xxxService.Start();
            }

            await _xxxService.Stop();
        }
    }


Surprisingly good stuff all in this section:

https://learn.microsoft.com/en-us/dotnet/core/extensions/workers


Code example found at:

https://github.com/dotnet/samples/blob/main/core/workers/background-service/App.WorkerService.csproj


Use dynamic configuration in a .NET background service:

https://learn.microsoft.com/en-us/azure/azure-app-configuration/enable-dynamic-configuration-dotnet-background-service?tabs=windowscommandprompt


No scope is created for a "hosted service" by default, so most get the common error about "Cannot consume scoped service XXXX from singleton 'Microsoft.Extensions.Hosting.IHostedService'."  To use scoped services within a background service:

https://learn.microsoft.com/en-us/dotnet/core/extensions/scoped-service?pivots=dotnet-6-0


Ok stuff here:

https://learn.microsoft.com/en-us/dotnet/core/extensions/windows-service

Comments

Popular posts from this blog

Upgrading to .NET8 from desktop versions 4.8.X

JSON Web Tokens

GHL > Set website so shorter URL address