Repository navigation
App does not Run as a service in a Windows Container #52416
Description
Description
Using the library Microsoft.Extensions.Hosting.WindowsServices and a builder like the following:
public static IHostBuilder CreateHostBuilder(string[] args)
{
return Host.CreateDefaultBuilder(args)
.UseWindowsService(options => options.ServiceName = "foobar")
.ConfigureServices((hostContext, services) =>
{
services.AddHostedService<Agent>();
});
}
When executing as a service in a Windows Container the following can be observed:
System event logs:
# Get-EventLog -LogName Application -Newest 10 | %{ $_.Message }
A timeout was reached (30000 milliseconds) while waiting for the foobar...
A timeout was reached (30000 milliseconds) while waiting for the foobar...
A timeout was reached (30000 milliseconds) while waiting for the foobar...
Application event logs:
# Get-EventLog -LogName Application -Newest 10 | %{ $_.Message }
Windows Management Instrumentation Service subsystems initialized successfully
Category: Microsoft.Extensions.Hosting.Internal.Host
EventId: 2
Hosting started
Category: Microsoft.Hosting.Lifetime
EventId: 0
Content root path: C:\Windows\system32
Category: Microsoft.Hosting.Lifetime
EventId: 0
Hosting environment: Production
Category: Microsoft.Hosting.Lifetime
EventId: 0
Application started. Press Ctrl+C to shut down.
Category: Microsoft.Extensions.Hosting.Internal.Host
EventId: 1
Hosting starting
Category: Microsoft.Extensions.Hosting.Internal.Host
EventId: 2
Hosting started
Category: Microsoft.Hosting.Lifetime
EventId: 0
Content root path: C:\Windows\system32
Category: Microsoft.Hosting.Lifetime
EventId: 0
Hosting environment: Production
Category: Microsoft.Hosting.Lifetime
EventId: 0
Application started. Press Ctrl+C to shut down.
It appears the the "host" (that the right name?) does not detect it's running as a service. So the app defaults to running as a console app.
Digging deeper, there's a check for "am I a service?" in Microsoft.Extensions.Hosting.WindowsServices.IsWindowsService().
runtime/src/libraries/Microsoft.Extensions.Hosting.WindowsServices/src/WindowsServiceHelpers.cs
Lines 18 to 31 in 01b7e73
| public static bool IsWindowsService() | |
| { | |
| if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) | |
| { | |
| return false; | |
| } | |
| var parent = Internal.Win32.GetParentProcess(); | |
| if (parent == null) | |
| { | |
| return false; | |
| } | |
| return parent.SessionId == 0 && string.Equals("services", parent.ProcessName, StringComparison.OrdinalIgnoreCase); | |
| } |
Looking at what this checks:
- Is Windows? Yes.
- Is there a parent process? Yes.
- Is this process named
services? Yes. - Is this process executing from session
0? No?!?
# pslist.exe -accepteula -t
Name Pid Pri Thd Hnd VM WS Priv
Idle 0 0 2 0 8 8 60
System 4 8 88 3565 3696 144 160
wininit 276 13 3 167 4194303 7276 1640
services 316 9 5 225 4194303 6832 2348
foobar 2908 8 10 241 4194303 25380 12688
# Get-Process -id 316 | select name,SessionId
Name SessionId
---- ---------
services 1
Apparently services doesn't have to run under session 0?
Other information
While "why are running an app in a Windows Container as a Windows Service? Don't do that." would be a completely valid answer.... We are using Windows Containers to provide short lived sandboxes for integration tests - in this case - testing a Wix installer, installing a .NET 5 based Windows Service (self-contained mode). It would be nice if we could continue doing so with .NET 5.
We were historically using TopShelf under .NET Framework, but we migrated to .NET 5. TopShelf does not perform this session 0 check, only the services name check: https://github.com/Topshelf/Topshelf/blob/03bde8963da8c057ffc6df07ef9600ffdf6047c1/src/Topshelf/Runtime/DotNetCore/DotNetCoreHostEnvironment.cs#L57-L80
Therefore, I propose removing that session id check going forward.
Activity
Silvenga commentedon May 7, 2021
If this proposal is acceptable, I would be happy to make a pr. 😸
eerhardt commentedon Jul 22, 2021
Getting help from @GrabYourPitchforks offline, the following approach was recommended for identifying if the current process is hosted as a windows service:
We can accomplish (1) above with calling:
runtime/src/libraries/System.ServiceProcess.ServiceController/src/System/ServiceProcess/ServiceController.cs
Lines 694 to 701 in 14d6532
Then p/invoke into QueryServiceStatusEx to get the service's PID. Comparing the current PID is straight-forward from there.
Moving to 7.0 and marking as "up for grabs".
Silvenga commentedon Jul 22, 2021
Sounds good! I'll see if I have time to work this in the near future.
Silvenga commentedon Jul 26, 2021
I'm not going to be able to work this any time soon. Needing to install native build sdk's/python, modifying PATH, etc. is a bit heavy for my current setup.
I don't suppose there's a way to work extensions without needing to build the whole runtime?
eerhardt commentedon Jul 26, 2021
Check out @ViktorHofer's response here:
#43118 (comment)
You can build the
srcproject with:and you can run the
testproject against .NET Framework with:So you can do some development without building the whole runtime.
Silvenga commentedon Jul 26, 2021
Oh, thanks - I didn't think about not building the solution (related to the Directory.Build.props I assume?).
My tooling hates this solution - removing the
$(NetCoreAppCurrent)resolves most of the problems, I just have to make sure not to commit that. 😹Check if current app is WindowsService by finding process id dotnet#5…
wrzucher commentedon Aug 20, 2021
I am trying to fix this issue but unfortunately, the described solution does not work.
QueryServiceStatusEx return 0 for service. I think, this happens because service is not running yet, it has status StartPending (I checked it) on the moment when we call QueryServiceStatusEx.
You could see my code here: wrzucher@e5ade03
So, I don't know how this problem could be fixed.
dmytro-pryvedeniuk commentedon Nov 15, 2021
The reporter proposes to delete session id check. Isn't it enough? Do you think it can cause some side-effects?
zryogi commentedon Nov 17, 2021
Please review #51269 (comment) as the cause of the issue may not be related only to the SessionId validation.
Is it possible that the "service" is not being created and spawned as an actual Windows Service but rather as a stand alone executable which expected behavior is to continue running at infinitum?
jhennessey commentedon Nov 23, 2021
I hit this issue as well and can confirm that getting rid of the
parent.SessionId == 0check fixed it for me.App does not Run as a service in a Windows Container
eerhardt commentedon Dec 6, 2021
I've created #62452 to remove the check.
App does not Run as a service in a Windows Container (#62452)
App does not Run as a service in a Windows Container (dotnet#62452)
[release/6.0] App does not Run as a service in a Windows Container (#…