1

We've created a new hosted service using .NET Core 3.1 and the WorkerService template.

We want to run this service as a "Windows Service".

If I run the program manually using a Powershell shell, it runs fine with no problems.

So I then added it as a windows service. To do this, I followed these steps:

  1. Added the Microsoft.Extensions.Hosting.WindowsServices package

  2. Added the following to CreateHostBuilder:

        public static IHostBuilder CreateHostBuilder(Serilog.ILogger logger, string[] args) =>
        Host.CreateDefaultBuilder(args)
            .UseWindowsService() // <-- added this line
            .ConfigureAppConfiguration(configurationBuilder =>
            {
                configurationBuilder.SetBasePath(Directory.GetCurrentDirectory())
                    .AddJsonFile("appsettings.json", optional: true);
            })
    
  3. Published it to a folder (zipped it and copied to server).

  4. Added it as a service:

PS C:\Windows\system32> sc.exe create MyService binpath= "C:\Program Files\Services\MyService.exe" 5. Opened the Services snap-in and started the service.

The snap-in shows that it has a status of "running". However, the program does not seem to actually do anything. It is not logging anything, including the most basic "Starting up" log message.

I even added a Seq sink on the off-chance that there was an IO problem preventing it from writing to a file. But nothing.

Can anyone identify what I am doing wrong?

onefootswill
  • 3,707
  • 6
  • 47
  • 101
  • Did you try deploying it on local machine using sc.exe ? – Chetan Jun 14 '21 at 04:07
  • @ChetanRanpariya I had not. But now I have. Same behavior. So something has to be off. I also ran it fine manually, using the Windows Terminal. So, the exact same exe which the sc.exe includes with the binpath flag. It executes without a problem using a shell. – onefootswill Jun 14 '21 at 04:33
  • 2
    Out of curiosity, what happens when you try something like "configurationBuilder.SetBasePath(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location))" Wondering if [this](https://github.com/dotnet/runtime/issues/36065#issuecomment-580354540) issue.. I.e. "Directory.GetCurrentDirectory() will point to %WINDIR%\system32" when running as a service – fuzzy_logic Jun 14 '21 at 05:09
  • I've had just come to the same conclusion and confirm that this has solved the issue. Was about to write an answer. But if you want to write an answer, I'll happily award it. Serilog is not logging to file. But it does log to Seq and the program is doing what it should. – onefootswill Jun 14 '21 at 05:31
  • 1
    Good to hear.. To write to file using Serilog, maybe something like "Host.CreateDefaultBuilder(args).UseSerilog((context, services, configuration) => configuration.ReadFrom.Configuration(context.Configuration).ReadFrom.Services(services).Enrich.FromLogContext().WriteTo.File($"{Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location)}\\logs\\log-.txt", rollingInterval: RollingInterval.Day, retainedFileCountLimit: 14).WriteTo.Console()).UseWindowsService()" – fuzzy_logic Jun 14 '21 at 06:09

1 Answers1

1

As per comment on issue 36065, when a .NET Core 3.1 worker service runs as a windows service "Directory.GetCurrentDirectory() will point to %WINDIR%\system32". Therefore to get the current directory, you could use some reflection and something like:

public static IHostBuilder CreateHostBuilder(Serilog.ILogger logger, string[] args) =>
    Host.CreateDefaultBuilder(args)
        .UseWindowsService() // <-- added this line
        .ConfigureAppConfiguration(configurationBuilder =>
        {
            configurationBuilder.SetBasePath(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location))
                .AddJsonFile("appsettings.json", optional: true);
        });

Worth noting, according to this comment, it's resolved in .NET 5.0

fuzzy_logic
  • 896
  • 11
  • 14
  • Not sure about the .NET 5 bit. I upgraded the project to .NET 5 and still saw the same behaviour. Either way, reflection sorted the problem. Love .NET reflection! – onefootswill Jun 14 '21 at 22:18
  • @onefootswill I was able to get working with .NET 5, however I still needed reflection for Serilog write to file. Have a read of [this](https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/windows-service?view=aspnetcore-5.0&tabs=visual-studio#use-contentrootpath-or-contentrootfileprovider). – fuzzy_logic Jun 15 '21 at 04:33
  • Cool. Will have a read. I configure Serilog with a JSON file, so need to use an absolute path (for the time being). And thanks for you help. – onefootswill Jun 15 '21 at 05:57