I have a dotnet core v.2.1 application that utilizes the "startup-class-by-environment-name-convention" to use different Startup
classes for different environment, e.g. development, staging and production. The Program.Main.CreateWebHost
method looks similar to this:
public static IWebHostBuilder CreateWebHostBuilder(string[] args)
{
var startupAssembly = Assembly.GetExecutingAssembly();
var webHostBuilder = WebHost.CreateDefaultBuilder(args)
.UseStartup(startupAssembly.FullName);
return webHostBuilder;
}
However, after upgrading to dotnet core v.2.2 (and the startup-switching still works great) I wanted to try out the in-process hosting capabilities. When switching to the in-process hosting model, and running locally with Visual Studio 2017 updated and IIS Express, I get this error running the application:
HTTP Error 500.30 - ANCM In-Process Start Failure
Common causes of this issue:
- The application failed to start
- The application started but then stopped
- The application started but threw an exception during startup
Troubleshooting steps:
- Check the system event log for error messages
- Enable logging the application process' stdout messages
- Attach a debugger to the application process and inspect
For more information visit: https://go.microsoft.com/fwlink/?LinkID=2028265
I checked all the logs, and all I could find was this:
<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
<System>
<Provider Name="IIS Express AspNetCore Module V2" />
<EventID Qualifiers="0">1007</EventID>
<Level>2</Level>
<Task>0</Task>
<Keywords>0x80000000000000</Keywords>
<TimeCreated SystemTime="2018-12-14T10:37:48.327935100Z" />
<EventRecordID>3693</EventRecordID>
<Channel>Application</Channel>
<Computer>[whatever]</Computer>
<Security />
</System>
<EventData>
<Data>Application '/LM/W3SVC/2/ROOT' with physical root '[whatever again]' failed to load clr and managed application. CLR worker thread exited prematurely</Data>
<Data>Process Id: 29836.</Data>
<Data>File Version: 12.2.18316.0. Description: IIS ASP.NET Core Module V2 Request Handler. Commit: ce8cf65589734f82b0536c543aba5bd60d0a5a98</Data>
</EventData>
</Event>
I read all the dotnet core in-hosting migrate 2.1 -> 2.2 whatever MSDN articles I could find, and tried a bunch of different set-ups, but could find no solution apart from using the default:
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>();
... Which will not do - I want to use the startup-switching together with the in-process hosting. Does anyone know how to achieve this, or have any suggestions on how to proceed with the troubleshooting?
EDIT: I got the answer I needed from @cilerler. For the sake of completeness, here's what was going on in my case:
The loading of my custom configuration files failed because this process depended on a call to Directory.GetCurrentDirectory()
, the result of which changes when switching to in-process hosting. Here's my original code for that part (shortened for brevity):
var basePath = $"{Directory.GetCurrentDirectory()}\\ConfigurationFiles";
builder.SetBasePath(basePath);
builder.AddJsonFile("some.config.json", false, true);
builder.AddJsonFile($"some.config.{context.HostingEnvironment.EnvironmentName}.json", true, true);
The crucial part is - again - the call to GetCurrentDirectory()
, so, to fix the issue, I changed the above as per the recommendation in the accepted answer, to:
var currentDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
var basePath = $"{currentDirectory}\\ConfigurationFiles";
builder.SetBasePath(basePath);
For further details, see the accepted answer ;)
According to aspnet-core-module article it says
GetCurrentDirectory returns the worker directory of the process started by IIS rather than the app's directory (for example, C:\Windows\System32\inetsrv for w3wp.exe).
which means config loader will not be able to find appsettings.*
files, or any other files such as custom config files, that depend on a GetCurrentDirectory
call. In order to solve it in your Program.cs right after public static void Main(string[] args) {
add the following line
Directory.SetCurrentDirectory(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location));
Also, in project file (e.g. MyProject.csproj) make sure that you have the following lines and appsettings.*
exists in output folder.
<ItemGroup>
<Content Update="appsettings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Update="appsettings.Development.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Update="appsettings.Production.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>