本文介绍了具有进程内托管的 Dotnet Core 多启动类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 dotnet core v.2.1 应用程序,它利用startup-class-by-environment-name-convention"为不同的环境使用不同的 Startup 类,例如开发、分期和生产.Program.Main.CreateWebHost 方法类似于:

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;
}

但是,在升级到 dotnet core v.2.2(并且启动切换仍然很好)后,我想尝试进程内托管功能.当切换到进程内托管模型并在本地运行 Visual Studio 2017 更新和 IIS Express 时,我在运行应用程序时遇到此错误:

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 错误 500.30 - ANCM 进程内启动失败

此问题的常见原因:

  • 应用程序无法启动
  • 应用程序启动,但随后停止
  • 应用程序启动但在启动过程中抛出异常

故障排除步骤:

  • 检查系统事件日志以获取错误消息
  • 启用记录应用程序进程的标准输出消息
  • 将调试器附加到应用程序进程并进行检查

有关详细信息,请访问:https://go.microsoft.com/fwlink/?LinkID=2028265

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>

我阅读了所有 dotnet core in-hosting migrate 2.1 -> 2.2 任何我能找到的 MSDN 文章,并尝试了一堆不同的设置,但除了使用默认设置之外找不到任何解决方案:

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?

我从@cilerler 那里得到了我需要的答案.为了完整起见,以下是我的情况:

I got the answer I needed from @cilerler. For the sake of completeness, here's what was going on in my case:

我的自定义配置文件加载失败,因为此过程依赖于对 Directory.GetCurrentDirectory() 的调用,当切换到进程内托管时,调用结果会发生变化.这是我对该部分的原始代码(为简洁起见已缩短):

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);

关键部分是 - 再次 - 调用 GetCurrentDirectory(),因此,为了解决该问题,我根据已接受答案中的建议将上述内容更改为:

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 ;)

推荐答案

根据 aspnet-core-module 文章

GetCurrentDirectory 返回由 IIS 启动的进程的工作目录,而不是应用程序的目录(例如,对于 w3wp.exe,为 C:WindowsSystem32inetsrv).

这意味着配置加载器将无法找到 appsettings.* 文件,或依赖于 GetCurrentDirectory 的任何其他文件,例如自定义配置文件 调用.为了在 public static void Main(string[] args) { 之后在您的 Program.cs 中解决它,添加以下行

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));

此外,在项目文件 (例如 MyProject.csproj) 中,请确保您有以下几行并且 appsettings.* 存在于输出中文件夹.

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>

这篇关于具有进程内托管的 Dotnet Core 多启动类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-28 15:34