Running an Asp.Net Core 2.* Web API as a Windows Service

At my current workplace there is a healthy hunger for new technologies and a pragmatic view of the software industry in our corner of the planet. As a Microsoft driven shop, previous reservations of moving to different ecosystems and operating systems have melted away with the arrival and wide adoption of .Net Core. After all the language is the same. The developers need "only" to catch up on their containers. When I joined a month ago as a tech lead, little did I know that putting my money where my mouth is would mean having to deal with outdated Microsoft documentation or even S.O answers to questions such as "How do I run an Asp.Net Core app as a windows service without IIS".
TL;DR add a reference to the NuGet package  Microsoft.Aspnetcore.Hosting.Windowsservices, publish and register your executable as a service.

A Prophecy?

Almost a year ago I wrote a blog post about porting full framework projects to core. Ever since I have written my share of .Net Core, Python and Bash script code, all happily deployed mostly on a Kubernetes cluster and if not as such then to a Cloudformation on AWS over Linux images. Life was good and scripts where flowing on the wires of communications and then life being life I had to look for a new place to work. To make a long story short, I get to lead a group of developers on how to port TopShelf based services to .Net Core and have them run as windows services (containers are down the road, until then windows services it is), as well as redefine the system's architecture and apply it little by little on a mission critical production system.

One of the ports is a WCF service turning REST over .Net Core. Nevertheless it still has to run as a service. The port was fairly easy, the code works like a charm. I had my Swagger setup and my client stubs ready with NSwag and it was time to deploy.

Eeny, meeny, miny, shift delete...

Go ahead and type "How to run ASP.Net Core as a service" in your favorite browser. Most likely the first results page will include these links
  1. A Microsoft article. This should be the ultimate guide right? Wrong!
  2. A DZone post. Informative but... no.
  3. This blog post. Nope
  4. This blog post. How about... no.
  5. A plethora of Stack Overflow answers.
All the above revolve more or less around the same answer in different versions of Asp.Net Core 2, ranging from preview to 2.2.  The gist of it is: Add a platform RID (such as win7-x64) in your project file, add some attributes denoting if the deployment mode is framework dependent or self contained (self contained is a good idea with some caveats... read through carefully), compile, publish and use the sc create command to register your service.


Me trying to wire up (or conjure) the correct parameter combinations

Read the manual they said

After following the steps described in each post carefully results varied. I had a file named apphost.exe which was supposed to be the bootstraper for the service DLL but threw an error all the time. And then I didn't or the self contained deployment went awry with some modern DLL hell over .Net Core 2.1 vs 2.1.6 update. 

One of them (namely number 4 in the list) suggested to change the netcoreapp2.1 moniker to net461 in order to produce an executable that could be run as a service, which is quite the opposite of going with .Net Core in the first place. All other posts suggested that by following their instructions an executable file (yes .exe) will be produced. That sounded (or rather read) very odd to me. .Net Core does not produce executable files. 

I decided to cleanup my code but leave the additions for running as a service as well as the 
Microsoft.Aspnetcore.Hosting.Windowsservices package , delete the extra properties in my project file, build, publish and see what is produced... And there it was, like an uncut diamond fresh out of a volcano... A .exe file produced out of a .Net Core project. I opened the command line and after a few seconds there it was. An ASP.Net Core, lean, mean Kestrel based, Windows service. Success!

Lessons (re)learned

In the jolly days of MFC I used to be skeptic of complicated solutions in Microsoft's web sites and documentation mainly because experience had taught me that they usually did not really work. Not even in the examples attached to them (I wonder in whose environments they did work though). This incident threw me back 20 years. Now I am back to being skeptic about the solutions provided in these docs. At least this time around I had the experience to think out of the box.

Finally, lest I forget, the link to a working solution. Happy Coding!

Comments

Popular posts from this blog

Tests code coverage in Visual Studio Code with C# and .Net Core

Visual Studio Code setup I use for C# development

Evaluating NDepend on current code base Part 1