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 ;)
No, each environment could only run one startup class. We couldn't run multiple startup class at same environment.
The Configure method is used to specify how the app responds to HTTP requests. The request pipeline is configured by adding middleware components to an IApplicationBuilder instance.
Multiple Startup ClassesAt runtime, the appropriate Startup class is selected when the app defines separate Startup classes for various environments. The class whose name matches the current environment is prioritized.
CreateDefaultBuilder performs the following tasks: Configures Kestrel server as the web server using the app's hosting configuration providers. For the Kestrel server's default options, see Configure options for the ASP.NET Core Kestrel web server. Sets the content root to the path returned by Directory.
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>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With