Jitendra
Jitendra

Reputation: 21

Hosting ASP.NET Core application in Windows Service with Single Executable gives wrong working directory path always

I have hosted ASP.Net core 3.1 application in Windows Service. It works fine and I am able to navigate to pages.

Now i am trying to change deployment as single executable file from "Produce single file" option in Publish settings. after this I started getting errors 404 for static files under wwwroot folder. below are the folders and actucal values:

Directory.GetCurrentDirectory() =  C:\WINDOWS\system32  - This is Correct as per documentation.

AppDomain.CurrentDomain.BaseDirectory = C:\WINDOWS\TEMP\.net\app_windows_servicename\yjzzq0br.phx\
// This should have been the installed application location.

hostingContext.HostingEnvironment.ContentRootPath= C:\WINDOWS\TEMP\.net\app_windows_servicename\yjzzq0br.phx\
// This should have been the installed application location.

This path contains extracted binaries but does not contain folder and content for wwwroot. If i manually copy wwwroot folder and content to this temp location then hosted asp.net core service under windows service serves the static files properly.

help me on this. Same behavior was observed in ASP.Net Core 3.0.1 also.

Upvotes: 2

Views: 1154

Answers (2)

Frank
Frank

Reputation: 1080

Works but only if UseContentRoot is applied to the IHostBuilder and not within ConfigureWebHostDefaults. Eg: Host.CreateDefaultBuilder(args).UseSerilog().ConfigureWebHostDefaults(...).UseWindowsService().UseContentRoot(...)

Upvotes: 0

musefan
musefan

Reputation: 48425

I don't know the exact reason why this happens, it seems like an intentional design decision though, but more information can be found here.

The linked post includes a workaround that I can confirm does resolve the problem. I will sum up the solution here:

In program.cs there is a method called CreateHostBuilder. By default, you will probably have something like this...

public static IHostBuilder CreateHostBuilder(string[] args)
{
    var builder = Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseStartup<Startup>();
        });

    builder.UseWindowsService();

    return builder;
}

To resolve the issue, you need to override the default content root and specific the same directory of the application EXE file. The can be done like so:

var pathToExecutable = System.IO.Path.GetDirectoryName(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName);
builder.UseContentRoot(pathToExecutable);

Note. It is worth noting that this doesn't seem to work when running in debug mode directly from Visual Studio, so it might be worth wrapping it in a condition. One simple option is to just check for the existence of an attached debugger like so:

if (!System.Diagnostics.Debugger.IsAttached)
{
    var pathToExecutable = System.IO.Path.GetDirectoryName(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName);
    builder.UseContentRoot(pathToExecutable);
}

Warning. There is some degree of assumption here that not having a debugger attached means it's running as a service. You should decide for yourself what condition works best for your needs. You could opt to use preprocessor directives to detect "release mode", for example.

Upvotes: 1

Related Questions