DEV Community

John Smith
John Smith

Posted on • Originally published at solrevdev.com on

Event Viewer Logs with .NET Core Workers as Windows Services

Back in the older classic windows only .NET Framework days, I would use a cool framework called TopShelf to help turn a console application during development into a running windows service in production.

Today instead I was able to install and run a windows service by modifying a .NET Core Worker project by just using .NET Core natively.

Also, I was able to add some logging to the Windows Event Viewer Application Log.

First, I created a .NET Core Worker project:

mkdir tempy && cd $_
dotnet new worker

Then I added some references:

dotnet add package Microsoft.Extensions.Hosting
dotnet add package Microsoft.Extensions.Hosting.WindowsServices
dotnet add package Microsoft.Extensions.Logging.EventLog

Next up I made changes to Program.cs, In my project I am adding a HttpClient to make external Web Requests to an API.

public static class Program
{
    public static void Main(string[] args)
    {
        var builder = CreateHostBuilder(args);
        builder.ConfigureServices(services =>
        {
            services.AddHttpClient();
        });

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

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .UseWindowsService()
            .ConfigureLogging((_, logging) => logging.AddEventLog())
            .ConfigureServices((_, services) => services.AddHostedService<Worker>());
}

The key line for adding Windows Services support is :

.UseWindowsService()

Logging to Event Viewer

I also wanted to log to the Application Event Viewer log so notice the line:

.ConfigureLogging((_, logging) => logging.AddEventLog())

Now for a little gotcha, this will only log events Warning and higher so the Worker template’s logger.LogInformation() statements will display when debugging in the console but not when installed as a windows service.

To fix this make this change to appsettings.json, note the EventLog section where the levels have been dialled back down to Information level.

{
    "Logging": {
        "LogLevel": {
            "Default": "Information",
            "Microsoft": "Warning",
            "Microsoft.Hosting.Lifetime": "Information"
        },
        "EventLog": {
            "LogLevel": {
                "Default": "Information",
                "Microsoft.Hosting.Lifetime": "Information"
            }
        }
    }
}

Publishing and managing the service

So with this done, I then needed to first publish, then install, start and have means to stop and uninstall the service.

I was able to manage all of this from the command line, using the SC tool (Sc.exe) that should already be installed on windows for you and be in your path already.

Publish:

cd C:\PathToSource\
dotnet publish -r win-x64 -c Release -o C:\PathToDestination

Install:

sc create "your service name" binPath=C:\PathToDestination\worker.exe

Start:

sc start "your service name"

Stop:

sc stop "your service name"

Uninstall:

sc delete "your service name"

Once I saw that all was well I was able to dial back the logging to the Event Viewer by making a change to appsettings.json, In the EventLog section I changed the levels back up to Warning level.

This means that anything important will indeed get logged to the Windows Event Viewer but most Information level noise will not.

Success 🎉

Latest comments (5)

Collapse
 
terryjdavis profile image
terryjdavis

I've followed the post but nothing is being written to the Event Log.

Collapse
 
0609ac2 profile image
Arvindraja🇮🇳

Thanks for sharing.
How can I implement logging for Linux. I want to generate a text file in linux and write text to it. How can I do that could you please suggest?

Collapse
 
katnel20 profile image
Katie Nelson

Nice article John.
Isn't .NET Core supposed to run on Linux?
How can you make that code work and install it as a Linux Daemon?

Collapse
 
solrevdev profile image
John Smith

Thanks Katie,

It does indeed, I code mostly on macOS and Ubuntu these days and .NET Core works great 👍

So, that’s actually something I’m going to do and blog about soon but to get you started if you notice the UseWindowsSevice() line well there’s also a UseSystemd() extension method that helps set that up.

Check out this article from Glenn I’ll be using it myself as a starter

devblogs.microsoft.com/dotnet/net-...

Hope this helps

Collapse
 
katnel20 profile image
Katie Nelson

Yes, it does. I knew there was no sc command and I wanted to know how to start things up in Linux.