runtime: UseWindowsService doesn't work correctly with single file executables
Describe the bug
.UseWindowsService() sets the base path to AppContext.BaseDirectory which ends up being something like C:\Windows\Temp\.net\FileUploader\blc0j22k.v0p when using a single file exe and running as a service. This prevents the appsettings.json files from being loaded if they’re saved alongside the exe which I’ve been told is an acceptable deployment scenario.
To Reproduce
Steps to reproduce the behavior:
- Using version
3.0.0-preview7.19362.4of packageMicrosoft.Extensions.Hosting.WindowsServices - Create an
appsettings.jsonwith a setting in it - In
.ConfigureServices(ctx, services)callctx.Configuration.GetValue<string>("SomeValue") - Publish the project using
dotnet publish --configuration Release --output artifacts /p:PublishSingleFile=true /p:PublishTrimmed=true - Install the service & run it
- The value in
appsettings.jsonwill not be loaded
Expected behavior
The appsettings.json stored alongside the exe should be loaded when running a single file exe as a service.
Current workaround
I originally was using the following code before I added in the Microsoft.Extensions.Hosting.WindowsServices package which I got from the asp.net core 2.2 docs:
var isService = !(Debugger.IsAttached || args.Contains("--console"));
if (isService)
{
using var process = Process.GetCurrentProcess();
var pathToExe = process.MainModule.FileName;
var pathToContentRoot = Path.GetDirectoryName(pathToExe);
Directory.SetCurrentDirectory(pathToContentRoot);
}
After adding this package I modified the code like so:
var builder = Host.CreateDefaultBuilder()
.UseWindowsService()
.ConfigureServices((ctx, services) =>
{
});
+if (WindowsServiceHelpers.IsWindowsService())
+{
+ using var process = Process.GetCurrentProcess();
+ var pathToExe = process.MainModule.FileName;
+ var pathToContentRoot = Path.GetDirectoryName(pathToExe);
+
+ builder.UseContentRoot(pathToContentRoot);
+}
else
{
builder.UseConsoleLifetime();
}
var host = builder.Build();
Depending on how you publish the application this might not be a bug but rather a documentation note. It seems worth mentioning though.
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Reactions: 6
- Comments: 16 (13 by maintainers)
I’d definitely prefer solving this via https://github.com/dotnet/core-setup/issues/7491
Given this, I’m going to mark this as External but leave it open for us to verify as 5.0 develops and we have the new single-file bundling logic to test out.
Just fyi,
Directory.GetCurrentDirectory()will point to%WINDIR%\system32for windows services so that’s why it would be good to have a generic API that tells you the location of whatever is the entry point (being entry point dll file fordotnet path/to/foo.dllor the main modulefoo.exefor app host with or without single file publishing).@BurhanEyimaya You can, just need to make sure to call is after
UserWindowsServiceAFAIK. https://github.com/dotnet/extensions/blob/275e691f7e575f208290d1cbb8cb450f4a3a85d6/src/Hosting/Hosting/src/HostingHostBuilderExtensions.cs#L35-L41Yes @dasMulli, the intention in the next version is for the
AppContext.BaseDirectoryto point to the apphost directory, as noted in the design.@anurse, I agree that an API to detect whether running from a single-file is useful in certain cases. There’s a proposal in the design to add this API in the next version.
Linking https://github.com/dotnet/core-setup/issues/7491 for transparency.
If the runtime adopts the behavior described in the design document this issue could likely be closed without action…