【问题标题】:Check if hosting server is IIS or Kestrel at runtime in aspnet core在 aspnet 核心运行时检查托管服务器是 IIS 还是 Kestrel
【发布时间】:2019-09-15 02:16:30
【问题描述】:

我目前在 Kestrel(本地)或 IIS InProcess(生产)下运行我的应用程序。

return WebHost.CreateDefaultBuilder(args)
    .ConfigureKestrel(options => options.AddServerHeader = false)
    .UseIIS()
    .UseStartup<Startup>();

我希望能够在运行时在控制器中获取托管服务器名称,以便实现以下目标:

if (hostingServer == "kestrel")
{
    DoSomething();
}
else
{
    DoSomethingElse();
}

在这种特定情况下,它是为了解决在 Kestrel 的响应标头中不支持非 ascii 字符的事实。理想情况下,我会删除非 ascii 标头,但目前它是旧版互操作性所必需的。

任何帮助将不胜感激。

【问题讨论】:

  • 你不能在启动时使用environment.IsDevelopment() 来实现吗?
  • 这就是我目前正在做的一种解决方法,但我们的验收测试在生产环境下使用 Kestrel 运行(可能应该暂存)

标签: c# iis asp.net-core .net-core kestrel-http-server


【解决方案1】:

检查进程名称对我不起作用,即使在使用 InProcess 托管在 IIS 中时,它仍然代理dotnet 进程(我的猜测是您需要获取父进程才能获取 w3wp 进程)。

NativeMethods.cs 中,.NET Core 内部调用IsAspNetCoreModuleLoaded(),可以在WebHostBuilderIISExtensions.cs 中找到。所以检查 IIS 可以用下面的代码来完成。

internal static class NativeMethods
{
    internal const string AspNetCoreModuleDll = "aspnetcorev2_inprocess.dll";

    [DllImport("kernel32.dll")]
    private static extern IntPtr GetModuleHandle(string lpModuleName);

    public static bool IsAspNetCoreModuleLoaded()
    {
        return GetModuleHandle(AspNetCoreModuleDll) != IntPtr.Zero;
    }
}

【讨论】:

  • 如果是真的,那是 IIS 吗?
  • 是的。然后应用程序托管在 IIS 进程中。
【解决方案2】:

最简单的方法可能是阅读System.Diagnostics.Process.GetCurrentProcess().ProcessName。如果是w3wpiisexpress,您知道主机是IIS/IIS Express,而dotnet(或使用自包含部署时的其他名称)表示Kestrel。这仅适用于进程中部署。如果您不在进程中,这将不起作用。在https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/aspnet-core-module了解更多信息

例子:

/// <summary>
/// Check if this process is running on Windows in an in process instance in IIS
/// </summary>
/// <returns>True if Windows and in an in process instance on IIS, false otherwise</returns>
public static bool IsRunningInProcessIIS()
{
    if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
    {
        return false;
    }

    string processName = Path.GetFileNameWithoutExtension(Process.GetCurrentProcess().ProcessName);
    return (processName.Contains("w3wp", StringComparison.OrdinalIgnoreCase) ||
        processName.Contains("iisexpress", StringComparison.OrdinalIgnoreCase));
}

【讨论】:

  • @jjxtra 感谢您的编辑,但显然问题本身是“或 IIS InProcess(生产)”,我正在回答这个问题。
  • 谢谢,这对我非常有用,因为我需要检测我是否托管在进程中的 IIS/IIS Express 中,以了解我是否低于 IIS MaxStackSize 限制(32 位为 256 KB , 64 位为 512 KB)。如果我使用 IIS/IIS Express 在进程外托管,这无关紧要,因为启动该进程的 exe/dll 对于确定堆栈大小很重要。因此,如果进程不是 w3wp.exe 或 iisexpress.exe,我可以确保我在正常的 CLR MaxStackSize 上运行(32 位为 1MB,64 位为 4MB),因为这些特定的 exe 文件在它们的堆栈大小限制标题。
【解决方案3】:

当应用程序启动时,托管方法可以在IApplicationBuilder.ServerFeatures 中公开。通过这里您可以找到引用 Kestrel 与反向代理配置的项目。

Startup.Configure 方法中可用的 IApplicationBuilder 公开 IFeatureCollection 类型的 ServerFeatures 属性。 Kestrel 和 HTTP.sys 各自只公开一个特性, IServerAddressesFeature,但不同的服务器实现可能 公开附加功能。可以使用 IServerAddressesFeature 找出服务器实现在运行时绑定了哪个端口。

该属性是一个集合,因此您需要过滤与 IIS 反向代理和 Kestrel 相关的特定托管方法。

【讨论】:

    猜你喜欢
    • 2021-05-19
    • 1970-01-01
    • 2017-09-01
    • 1970-01-01
    • 2014-03-07
    • 2013-03-09
    • 2017-11-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多