【问题标题】:Programmatically determine if code is running under IIS Express以编程方式确定代码是否在 IIS Express 下运行
【发布时间】:2012-03-21 09:03:57
【问题描述】:

我什至不确定这是否可行,但我希望能找到线索来确定当前正在执行的代码是否在 IIS Express 下运行。到目前为止我最好的近似值,这是非常骇人听闻的,并且肯定会在某些时候失败/破坏:

bool IsExpress = 
  Request.ServerVariables["SERVER_SOFTWARE"] == "Microsoft-IIS/7.5"
  && Int32.Parse(Request.ServerVariables["INSTANCE_ID"]) > 1000000000;

当然必须有更好的方法。我对 Application、Server 和 Request 对象的检查似乎没有发现任何可以提供更好洞察力的东西。也许我只需要看看其他对象?

更新:

我真的很好奇是否有办法检测到这一点 - 在这一点上它真的很学术,我没有迫切需要使用它。原来的问题是成立的。但本着回应 cmets 的精神,特别是我有兴趣回答来自本网站上另一个问题/答案的批评:How to search the server's MIME map。批评是发布的答案不适用于 IIS Express,仅适用于传统的 IIS 实例。 IIS Express 将 MIME 配置存储在 applicationhost.config XML 文件中,我想更新该答案以提供一种方法来为 IIS Express 返回该信息。我当然可以添加一些从 XML 中获取适当值的代码(是的,LINQ to XML!),但我真的想让它更智能。需要明确的是,我不需要帮助解析该文件 - 只是在尝试检测代码当前是否在 IIS Express 引擎中执行时更优雅。

更新 2:

IIS 8.0 Express Beta 是released this week,它进一步表明我的问题中的方法很脆弱并且会崩溃。虽然针对特定版本不会破坏交易,但最好考虑到这一点并尝试确保代码至少可以与今天的已知版本一起使用。

【问题讨论】:

  • 你的目标是什么?为什么要检测到这一点(也许还有其他方法可以实现您的目标)?
  • 如果它在 IIS Express 中运行,你想以不同的方式处理什么?也许这是您需要问的问题,而不是如何检测 IIS Express。 “在调试中运行时,我如何使用 _____ 而不是 _____?”,例如。
  • 希望集中在检查一些配置元素 - 使用 DirectoryEntry("IIS:/localhost/W3SVC/") 与解析控制 IIS Express 的 applicationhost.config 中的 XML。
  • 再一次,你的目标到底是什么?为什么应用程序应该知道托管环境?

标签: c# iis iis-express


【解决方案1】:

检查当前进程名称是否有用?

bool isExpress = 
  String.Compare(Process.GetCurrentProcess().ProcessName,"iisexpress") == 0;

普通 IIS 在内存中的w3wp.exe 下运行。

【讨论】:

  • 这是 IIS 7.5 的 w3wp - 但我不确定 IIS 的不同版本。我知道对于真正的旧版本的 IIS 来说这是不同的......
  • @debracey 是的,对于旧版本,它将是 aspnet_wp.exe
  • 我使用这种方法遇到的唯一潜在问题是 System.Diagnostics.Process 类需要完全信任。否则似乎就像一个魅力。
  • 我测试了代码,应该改成:bool isExpress = String.Compare(Process.GetCurrentProcess().ProcessName,"iisexpress") == 0;
【解决方案2】:

Oran Dennison 的回答对我来说不再适用于 dotnet core。

我先创建了一个可以获取父进程的方法来扩展它:

/// <summary>
/// A utility class to determine a process parent.
/// </summary>
/// <remarks>
/// From https://stackoverflow.com/a/3346055/240845
/// </remarks>
public static class ParentProcessUtilities
{
    /// <summary>
    /// Gets the parent process.
    /// </summary>
    /// <param name="process">The process to get the parent of</param>
    /// <returns>The parent process.</returns>
    public static Process Parent(this Process process)
    {
        return GetParentProcess(process.Handle);
    }

    /// <summary>
    /// Gets the parent process of the current process.
    /// </summary>
    /// <returns>An instance of the Process class.</returns>
    public static Process GetParentProcess()
    {
        return Process.GetCurrentProcess().Parent();
    }

    /// <summary>
    /// Gets the parent process of a specified process.
    /// </summary>
    /// <param name="handle">The process handle.</param>
    /// <returns>The parent process.</returns>
    public static Process GetParentProcess(IntPtr handle)
    {
        ProcessInformation pbi = new ProcessInformation();

        // Note, according to Microsoft, this usage of NtQueryInformationProcess is 
        // unsupported and may change
        int status = NtQueryInformationProcess(
            handle, 0, ref pbi, Marshal.SizeOf(pbi), out _);
        if (status != 0)
        {
            throw new Win32Exception(status);
        }

        try
        {
            return Process.GetProcessById(pbi.InheritedFromUniqueProcessId.ToInt32());
        }
        catch (ArgumentException)
        {
            // not found
            return null;
        }
    }

    [DllImport("ntdll.dll")]
    private static extern int NtQueryInformationProcess(
        IntPtr processHandle, int processInformationClass,
        ref ProcessInformation processInformation, int processInformationLength, 
        out int returnLength);

    /// <summary>
    /// Used in the NtQueryInformationProcess call.
    /// </summary>
    [StructLayout(LayoutKind.Sequential)]
    public struct ProcessInformation
    {
        // These members must match PROCESS_BASIC_INFORMATION
        internal IntPtr Reserved1;
        internal IntPtr PebBaseAddress;
        internal IntPtr Reserved2_0;
        internal IntPtr Reserved2_1;
        internal IntPtr UniqueProcessId;
        internal IntPtr InheritedFromUniqueProcessId;

    }
}

然后,您可以执行以下操作:

public bool IsUnderIisExpress()
{
    var currentProcess = Process.GetCurrentProcess();
    if (string.CompareOrdinal(currentProcess.ProcessName, "iisexpress") == 0)
    {
       return true;
    }

    var parentProcess = currentProcess.Parent();
    if (string.CompareOrdinal(parentProcess.ProcessName, "iisexpress") == 0
        || string.CompareOrdinal(parentProcess.ProcessName, "VSIISExeLauncher") == 0)
    {
        return true;
    }

    return false;
}

【讨论】:

【解决方案3】:

如果您不介意使用 COM 级 API,可以使用 IIS 版本管理器 API

http://msdn.microsoft.com/en-us/library/gg418429.aspx

在此 SO 帖子中有一些关于如何使用它的讨论:Starting and stopping IIS Express programmatically - 不完全是您想要的,但他们确实讨论了使用 API。

编辑:我应该补充一点,我自己没有尝试过,但看起来很有希望,祝你好运!

【讨论】:

  • 我研究了这个 API,但我有两个保留意见:一个是它被标记为“不打算直接从你的代码中使用”——不是破坏交易,但也不鼓励。二我不确定如何(或者即使你可以)将当前执行的代码连接到从 API 返回的实例。也许通过匹配 URL 或其他方式。
  • 不知道你在做什么——但我会在应用程序池启动时将 IIS 版本拉到你的代码中(可能是你自己托管的enum),然后只是将其存储在静态变量中——不要每次都去查询 COM API。如果不重新启动您的应用程序,服务器类型显然无法更改。
  • 如果我新建 IISVersionManager 类,我可以获得机器上可用的 IIS 实例列表,但我无法将该 IISVersion 接口映射到在 IIS 实例内部执行的代码。我真的不明白这个 COM API 如何帮助我了解当前运行的代码是否在 IIS Express 中——不仅仅是 IIS Express 可用。也许代码示例可以帮助澄清您的建议?
  • 哦,好的 - 是的 - 这是一个很好的观点......回到绘图板
【解决方案4】:

我们能不能不试试看一个或多个limitation of IIS Express 是否有效,如果有效则不是 IIS Express。示例 IIS Express 不支持共享点服务

【讨论】:

  • 您能否分享一下您认为可以可靠测试哪些特定(或其他)限制?
  • 某种查询,比如环境变量 %IISBin% 会是一个很好的提示吗?或查询共享点服务,如果结果不受支持-我们知道我们在 IIS Express 上
  • 测试 %IIS_BIN% 可能有效,看起来只有 IIS Express 设置了该变量。唯一的问题是 EnvironmentPermission 类可以设置为拒绝访问这些变量。我不知道您所说的“查询共享点服务”是什么意思 - SharePoint 是您可以安装的产品,而不是 IIS 的原生产品。
猜你喜欢
  • 1970-01-01
  • 2011-10-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-11
  • 1970-01-01
相关资源
最近更新 更多