Runtime: System.ServiceProcess.ServiceController & ServiceBase

Created on 11 Feb 2016  路  43Comments  路  Source: dotnet/runtime

We've had requests to port https://github.com/topshelf/topshelf to .NET Core. To do this, we would love to be able to query if we had access to the SCM and act as needed so we don't need to ship a version targeting both core & full profile.

area-System.ServiceProcess enhancement

Most helpful comment

Sure @GuardRex -- I'm happy to keep this open if it's coming. We'll happily port Topshelf to Core, we're getting plenty of requests for it.

All 43 comments

@TravisTheTechie There is a System.ServiceProcess.ServiceController package (https://www.nuget.org/packages/System.ServiceProcess.ServiceController/). The exposed API surface is visible at https://github.com/dotnet/corefx/blob/master/src/System.ServiceProcess.ServiceController/ref/System.ServiceProcess.ServiceController.cs

Does that help? Or have I misunderstood the question entirely? :smile:

Is that package implemented on Core now? It appears to just be a place holder.

I believe that this would enable us to easily port Topshelf to Core.

Well, it's at least real enough that it has tests that intermittently fail on my machine :) (#6029)

I just cracked open the 4.1.0-beta-23516 package (the most recent one on nuget; though there are newer ones in the daily feed) and it has a .NET Core implementation as well as the full framework type forwarder library. So, hopefully you're good to go!

That seems to work... I've having a couple other issues.

  • ServiceAccount is not exposed for System.ServiceProcess.ServiceController package
  • System.Configuration.Install.Installer does not appear to be part of the Core surface area, is this correct?
  • It appears that System.Diagnostics.TraceSource is being transitioned to System.Diagnostics.Tracing -- is there any documentation on that transition?

@bartonjs

Thanks for chasing this up! I didn't know we exposed this API. Should have checked before asking @TravisTheTechie to file it. Sorry @TravisTheTechie!

System.Configuration.Install.Installer does not appear to be part of the Core surface area, is this correct?

That's correct. There are also no plans to bring this to .NET Core. The replacement is to use Windows Installer XML (or any other powerful setup tool). In general, you should avoid custom actions as those make installers more fragile.

It appears that System.Diagnostics.TraceSource is being transitioned to System.Diagnostics.Tracing -- is there any documentation on that transition?

TraceSource is still available on .NET Core. It's in the System.Diagnostics.TraceSource package.

It seems the only part missing is ServiceAccount.

@bartonjs, do you know why this enum was not exposed? I assume it's because the controller doesn't need it, only the installer part?

@terrajobst filing the issue made me actually dig into the problem of porting over Topshelf some more, so maybe it was worth to be misled anyways ;)

I think not having access to the Installer class will mean porting will be non-trivial. We modify the image path after installation (e.g. https://github.com/Topshelf/Topshelf/blob/develop/src/Topshelf/Runtime/Windows/HostInstaller.cs#L51) and the whole point of Topshelf is to avoid WiX/installers. We might be able to figure out some work arounds in time, but obviously not the same way things have been done.

Thanks!

@terrajobst No idea, my only relationship with this library is I was reporting it as intermittently failing a test while @TravisTheTechie was reporting it as not existing :smile:.

Hey @pallavit, @weshaggard mentioned that did the port. Could you answer this question:

do you know why this enum was not exposed? I assume it's because the controller doesn't need it, only the installer part?

do you know why this enum was not exposed? I assume it's because the controller doesn't need it, only the installer part?

That is correct. ServiceAccount enum is only used by the installer and not the controller and hence it was not exposed.

@TravisTheTechie

I'm suprised you didn't ask for ServiceBase. Does this mean you're only controlling native services?

No, Topshelf would require ServiceBase, but when I converted it, there wasn't an error for it. I assume if it's not in the Core surface area then I'd end up with that error after whatever error was masking that was fixed.

It appears this just won't be possible. You're not exposing many of things we require for Core, so I think we'll just consider this a non-started for now.

@terrajobst Asking over in https://github.com/aspnet/Home/issues/1386 ... looks like ServiceBase going to Core will help get Core apps on Windows Services on Nano (current ServiceBase is net451).

This issue is marked "port-to-core" and "Future," but it's closed. Is there any status/issue for ServiceBase getting ported to Core?

@TravisTheTechie Would you mind re-opening this to keep it on the team's radar? They marked it "port-to-core" and "Future," but I fear that they aren't looking it with it being closed. As it stands, we can't make Windows Service apps AFAICT for Nano Server without ServiceBase and without having to resort to 3rd party software or hacks (e.g., GPO startup scripting or maybe NSSM). cc/ @shanselman @DamianEdwards

Sure @GuardRex -- I'm happy to keep this open if it's coming. We'll happily port Topshelf to Core, we're getting plenty of requests for it.

Thanks. Now, I hope they'll just jump in and say if this could get off of "Future" and onto 1.1 or whatever, and perhaps any thoughts on running a Core app as a Windows Service on Nano.

[EDIT] "thoughts on running a Core app as a Windows Service on Nano" >> meaning:

(1) Would running a console app as a GPO startup script with a hook for ...

c# [DllImport("Kernel32")] private static extern bool SetConsoleCtrlHandler(EventHandler handler, bool add);

be a good approach?
... or ...
(2) Wait for the ASP.NET Core Module to get a "warmup/auto-start" feature that will start an app (perhaps make an initial request) when the AppPool fires up. Then, the app with Always On should stay live and could be used as a poor-man's background service. https://github.com/aspnet/IISIntegration/issues/161
... or ...
(3) NSSM https://nssm.cc/ is 64-bit. Maybe it could handle a console app-as-a-service scenario? Any idea if that would work?

Any comments, tips, or other ideas?

cc @babkin123 Had similar porting issues with ServiceBase, and had insights to help to port to core. Would you be interesting in making a contribution here?

Topshelf is a fantastic product, and I have used it a lot in the past, but of course it's not x-platform. For an x-platform server app deployed into a container like Docker, just using a console app is a more likely, with the container configured to auto-restart. If I had to use a mechanism to keep it up and running outside of a container I would use something like Task Scheduler on Windows or Systemd or Upstart. In that approach you don't need to plug into a non x-platform approach. So I can understand why the team don't consider this a priority as its not really "tomorrow's" story for server side code.

We have been using .net Core since the Alpha stage. We have several production apps running in .net Core. We do not understand the lack of attention to .net Core running as a Windows service or Linux/MacOS service/daemon. We believe it would be a huge mistake for .net Core not to support services/daemons as a first class citizen. Even the AspNet.Core.Hosting.WindowsServices package is something, but we are mainly interested in services that are using TcpListener or just a stateless service that does some work. We use services for so many things...it is hard to imagine that we must "wrap" a .net Core app in a legacy .net application to run as a windows service. Are there any updates to this story?

@bbunderson There was a "big" discussion recently at https://github.com/aspnet/Home/issues/2022
since it is virtually unlinkable, @DamianEdwards wrote:

The list of things to port to .NET Core after that currently includes ServiceBase (to support .NET Core Windows Services). No timeline yet other than it鈥檚 next (timelines obviously get more concrete as we work down the list). We鈥檒l build on this list as we go based on customer feedback.

Since we also want to host .NET Core applications as windows service (and not require / rely on customers to upgrade their .net framework / windows server versions), I created a small wrapper library that gives the minimum set of capability needed (run as service supporting start&stop, install&uninstall services - "CreateOrUpdateService" about to be released soon). If you can depend on 3rd party libraries I suggest trying it if it unblocks you: https://github.com/dasMulli/dotnet-win32-service

@Drawaes even made a youtube video on how to use it 馃槈

And I can say after a few months in a number of services in prod it has worked perfectly.

@dasMulli Are you an MVP? ... or has @shanselman and/or @DamianEdwards done anything to make that happen? I'm just say'in ... It would be great if MS recognized your contributions.

Anyone can nominate him :)

There's a BIG difference between "anyone nobody" and "anyone that can make a phone call and it happens."

haha no I'm not.

back to the point: Also don't forget that ServiceBase has usually some integration with other technologies such as the ServiceInstaller class which is recognised by InstallUtil.exe.
And there's no event log support at the moment (that I know of) which is commonly used by applications run as a service.

FYI - We are taking a look at this. We're looking to do this and a bunch of other libraries that will help people run their existing code on .NET Core. Note sure yet whether InstallUtil will be in scope though.

To show that its being more actively investigated, I'll move it to the 2.1 milestone :)

Speaking of existing code: A lot of code using ServiceBase uses Environment.UserInteractive in it's startup path to determine if it was launched from a console or as a service. AFAIK CoreCLR always returns true for this. full fx does a very specific API call to query user object flags and tests for a flag described as Window station has visible display surfaces. Not sure if that would work on nano server..
TopShelf checks the name of the parent process for a well-known name. which seems fragile but probably the best approach here.
I resorted to suggesting to add an additional command line parameter which may conflict with programs processing the args but is what many other native applications do (e.g. dockerd).

Since linux daemons have been mentioned in the thread (and I was asked on Slack a couple of times): Everything except windows happily runs "normal" executables as daemons (via rc systems / systemd on linux, launchd on mac). This is enough to create a start-&stoppable service. For advanced functionality, the application would need to react to Unix signals. An API for this is tracked by https://github.com/dotnet/corefx/issues/3188 already. It's really only windows that requires applications to perform quite complex API calls for services (because the service model is quite advanced and has a lot of features which typical .net services use only a few percent of)

We have moved all of our "debug" / logged to console ones to
If (buffer.isattached || --interactive) it's nicer in the end and a better xplat story

I'm doing some investigations by porting the code to core. Beyond the EventLog dependency which I've commented out I've ported ServiceBase (not tested it yet) on windows. I'm now digging into the ServiceInstaller/ServiceProcessInstaller stuff which seems like it is going to a rats nest of installer stuff.

What to you guys think about how to handle installing? As long as you have ServiceBase and some script/installer to install the service I assume you don't care if it uses the Service[Process]Installer stuff correct? Or do folks have direct dependencies on those types as well?

Personally we use TopShelf for managing the start and stop of service and Octopus Deploy for installing and updating the service.

I would say TopShelf will depend on some of those Installer types since they offer a good way to configure the values for the service and some people will use that to set up the service.

Looking at https://github.com/Topshelf/Topshelf/blob/develop/src/Topshelf/Runtime/Windows/HostInstaller.cs it seems that Topshelf has a decent dependency on the Installer abstractions. @TravisTheTechie Do you guys feel like those are the best abstractions for your scenarios?

It would seem there are a few scenarios at play here.

  1. Writing a service using ServiceBase and running it on Windows (and Linux later)
  2. Providing all the necessary components for service frameworks like TopShelf to work as they do on full .NET Framework.

I'm going to first focus on (1) and see what reasonable options we have for (2).

Personally we believe top priority would be the ServiceBase. SC.EXE can always be used to install on windows.

Agreed. I will focus on ServiceBase first. What do folks think about the dependency on EventLog? Do you depend on the event logging for your services?

I also agree that SC.exe is enough for our use. Also the logging to eventlog is something that we have surpassed in our environment, using the ILoggerFactory for everything these days. The only time we are stuck at the eventlog is if there is an actual .net binding or DLL loading problem. You can always log to the eventlog manually.

I agree with Drawaes. Logging should stay at an abstracted layer. We just rewrote our service hosting package and removed Event Logging from it.

@weshaggard I have never really like the Installer abstractions, but mostly because we've always had to work around them (e.g. editing the image path after installation). However, I don't have a good handle on what the abstractions would even look like to support other service platforms.

Our first goal would to have something we could compile once, run on Windows as a service with the installer, and run as a console application on every platform. The installer can throw "not supported" exceptions for unsupported platforms and I still consider that a win for us. I started looking at decoupling all the Windows related stuff and it turns out we have coupling and leaky abstractions that it would be a big enough challenge we haven't been interested in undertaking yet.

Install concerns would be a nice API addition to ServiceController. In my lib I just made a monster-method to register and update a service and a method to remove it again. It supports just the "single process > single service" model and would need to be run with administrative rights. But running this as part of an MSI (calling the program with --register-service) works great.

Install concerns would be a nice API addition to ServiceController.

That might be an approach we can take but for now I'm focusing on ServiceBase and porting existing APIs. If we want to add new APIs we should file another issue to request those.

I'm about to go on vacation starting tomorrow and through next week, but I wanted to update the issue with my current progress. I've ported ServiceBase into the System.ServiceProcess.ServiceController library and I've ported some of ServiceInstaller into a TestServiceInstaller that I intend to use for testing. However I've not yet gotten any tests written and running.

For those that are interested the work is in my fork https://github.com/weshaggard/corefx/tree/ServiceBase. If anyone is interested on working on some tests for it while I'm out please feel free to pick-up those changes and work on it, and feel free to submit a PR with my changes including some tests. If not I will pick this up again in a couple weeks and finish it.

Great progress! Just out of curiosity the namespace was System.ServiceProcess for ServiceBase. I thought possibly putting it in System.ServiceProcess would be more clear...because System.ServiceProcess.ServiceController seems like it should only control services versus actually instantiate them. And I think @dasMulli may have assumed the same thing...when he was talking about the installer being in ServiceController.

Don't get me wrong...we will take the functionality/API anyway we can get it, but I was just curious.

@bbunderson it is still in the System.ServiceProcess namespace it is just in the System.ServiceProcess.ServiceController library right now. We have a System.ServiceProcess library in .NET Core but is is currently only a shim (i.e. type-forwards types only) and putting into that library will cause unnecessary restrictions because of the potential conflicts with .NET Framework. We could definitely consider putting it into another library but for now I figured I would keep it in the closest library we have which is System.ServiceProcess.ServiceController.

That makes total sense. Thanks for the insight, and thanks for attention to this matter. I think this will be a great addition and solve so many use cases.

As a quick update to let folks know I've not forgotten about this issue. This is still on my list but right now we have a lot of folks on vacation and I'm on point for finishing our .NET Core 2.0 release which is my top priority. Once that settles down over the coming weeks I will get back to this.

Finally got through the testing, which is a challenge, PR https://github.com/dotnet/corefx/pull/22920 is out for those that are interested to review.

Was this page helpful?
0 / 5 - 0 ratings