Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

API Proposal: ServiceBase.IsRunningInWindowsService #29252

Open
davidfowl opened this issue Apr 13, 2019 · 20 comments
Open

API Proposal: ServiceBase.IsRunningInWindowsService #29252

davidfowl opened this issue Apr 13, 2019 · 20 comments
Labels
api-needs-work API needs work before it is approved, it is NOT ready for implementation area-System.ServiceProcess
Milestone

Comments

@davidfowl
Copy link
Member

We recently added an API to detect if a .NET process was being lauched as a windows service (dotnet/extensions#1369). I believe this belongs in SeviceBase as it would be useful to have this feature outside of our hosting wrapper.

public class ServiceBase
{
    public static bool IsRunningInWindowsService { get; }
}

I'm open to other names.

  • IsRunningUnderWindowsService

cc @danmosemsft

@analogrelay
Copy link
Contributor

Example implementation: https://github.com/aspnet/Extensions/pull/1369/files

@danmoseley
Copy link
Member

@Anipik owns this area. Why is the API useful?

@davidfowl
Copy link
Member Author

We use it in our hosting layer to make the windows service specific logic noop. The benefit being that we can light up specific behavior when running in that context (like hooking into the lifetime events). This means my application runs in both modes (service or self hosted) seamlessly.

We’ve also had a customer ask us for this logic because they wanted a change to write some service specific logic in their startup.

@danmoseley
Copy link
Member

@anurse is that method documented, eg there is some reason to believe the service host process name won't change in future Windows versions?

I don't feel strongly but Im inclined to think we would want more evidence of need. If it was wrapping something like ::IsAService() it would be a lower bar in my mind.

@davidfowl
Copy link
Member Author

I just described how we use it. What evidence are you looking for? Are you not convinced that there are scenarios where knowing that you are running in a windows service is useful?

If windows changes it in the future we’ll update the code. If you know of a better way to detect that scenario there’ll be no pushback

@Wraith2
Copy link
Contributor

Wraith2 commented Apr 14, 2019

I believe this would be useful. In the past I've hooked up a log reader if running outside a service so I can direct the output to a user interface.

@danmoseley
Copy link
Member

if this was on ServiceBase the app would require a reference to the compat pack which it might not otherwise need. On the flip side, it is very Windows specific...

@davidfowl
Copy link
Member Author

@danmosemsft do yo have a proposal? Where would it live?

@analogrelay
Copy link
Contributor

There is Environment.UserInteractive which checks if the application is running in an "Interactive Session".

From the docs:

The UserInteractive property reports false for a Windows process or a service like IIS that runs without a user interface. If this property is false, do not display modal dialogs or message boxes because there is no graphical user interface for the user to interact with.

In my initial cursory testing, a console app reports Environment.UserInteractive as true.

We might need further testing here, but it may serve our purpose. It's not guaranteed to indicate that you're in a Windows Service though since there may be other non-Windows Service non-Interactive scenarios.

@Tratcher
Copy link
Member

That would also include scheduled tasks.

@analogrelay
Copy link
Contributor

That's what I was looking for :). I figured there might be a counter-example here.

@davidfowl
Copy link
Member Author

Doesn't that also report true when running in IIS?

@danmoseley
Copy link
Member

danmoseley commented Apr 16, 2019

As an aside, I had a quick look at the service related Win32 API and I didn't see an alternative way to check the current process is a service. The API's all deal with handles or service names (from which you get the handle). I don't see a way eg to enumerate services from a process handle.

Ideally we could get hold of the services parent process by a more robust method than using its name, but I don't know how.

@MarcoRossignoli
Copy link
Member

Name+path(%SystemRoot%\System32\services.exe)+Environment.UserInteractive ?

@MarcoRossignoli
Copy link
Member

MarcoRossignoli commented Apr 16, 2019

Another idea could be check associated windows station name, from Windows Internals 6:

Unless other directed, the Windows subsystem associates services running in the local system account with a nonvisible windows station named Service-0x0-3e7$ that all noninteractive services share.
...
However only processes owned by the system and Windows services run in session 0; all other logon sessions, including those of console users, run in different session. Any windows displayed by process in session 0 is therefore not visible to the user.

Check for Service-0x + login session identified + $
I did some check and it works also under IIS

image

The only issue is in case of SERVICE_INTERACTIVE_PROCESS flag for LocalSystem account...process will be associated with WinSta0, this is however not recommended for security reason and supported for backward compatibility.

@danmoseley
Copy link
Member

@Anipik @maryamariyan please limit 3.0 milestone to issues that must be fixed to ship 3.0.

@terrajobst
Copy link
Member

terrajobst commented Jul 9, 2019

Conclusion

  • The location makes sense because if the API returns true, consumers are likely ending up using APIs on ServiceBase
    • It seems there might be other scenarios where pulling in ServiceBase is not desirable.
  • We should consider shortening the name to IsRunningAsService as Windows is implied (the entire type is Windows-specific)
  • We can still expose a platform-agnostic API (that detects, say, Windows services and Linux daemons) but that's out of scope for this scenario

There are more questions. It seems someone needs to sit down and go through the Windows SCM APIs to see how this can be made reliable. There is also the question whether we need an API to return this for other processes, and not just the current one. Windows also allows hosting multiple services in a single process.

We also need to decide what, if any, the cross-platform angle is. For example, Windows might support multiple services by a single process. Daemons might not. It seems safer to scope this API to be Windows-only. However, it means we shouldn't burn a name like Process.IsRunningAsService, for instance.

@george-chakhidze
Copy link

Environment.UserInteractive always returns true in .NET Core. Maybe, while at it, you could properly implement this API as well?

@danmoseley
Copy link
Member

@george-chakhidze yep, this was done for 5.0. And as was pointed out above, it is not the same as this proposed API, although for some use cases it may be enough.

@msftgits msftgits transferred this issue from dotnet/corefx Feb 1, 2020
@msftgits msftgits added this to the 5.0 milestone Feb 1, 2020
@maryamariyan maryamariyan added the untriaged New issue has not been triaged by the area owner label Feb 23, 2020
@danmoseley danmoseley modified the milestones: 5.0.0, Future Jun 18, 2020
@ericstj ericstj removed the untriaged New issue has not been triaged by the area owner label Jul 9, 2020
@KalleOlaviNiemitalo
Copy link

In C++, I just call StartServiceCtrlDispatcher, and if that fails with ERROR_FAILED_SERVICE_CONTROLLER_CONNECT, then I know I'm not running as a service.

The equivalent thing was not feasible to implement on .NET Framework because ServiceBase.Run would handle the error by popping up a Windows Forms message box. That was removed in the .NET Core port but the method still logs the error to the console and to event logs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api-needs-work API needs work before it is approved, it is NOT ready for implementation area-System.ServiceProcess
Development

No branches or pull requests