31

I am not sure this is even possible, but I am hoping for a clue as to determine if the code that is currently executing is running under IIS Express. My best approximation so far, which is incredibly hackish and will certainly fail/break at some point:

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

Certainly there has to be a better way. My examination of the Application, Server and Request objects didn't seem to reveal anything that might provide better insight. Perhaps I just need to look at some other object?

Update:

I am really curious if there is a way to detect this - it is really academic at this point I don't have a burning need to use it. The original question stands. But in the spirit of responding to the comments, specifically I am interested in answering a criticism from another question/answer on this site: How to search the server's MIME map. The criticism is that the posted answer does not work for IIS Express, only traditional IIS instances. IIS Express stores the MIME configuration in the applicationhost.config XML file and I would like to update that answer to provide a way to return that information for IIS Express as well. I could certainly just add some code that grabs the appropriate value from the XML (Yay for LINQ to XML!) but I would really like to make it smarter. To be clear, I don't need help parsing that file - just something more elegant in trying to detect if code is currently executing in the IIS Express engine.

Update 2:

IIS 8.0 Express Beta was released this week, and it further goes to show that the approach in my question is brittle and will break. While it isn't a deal breaker to target a specific version, it would be nice to account for that and try to ensure the code will work with at least the known versions today.

Community
  • 1
  • 1
Goyuix
  • 23,614
  • 14
  • 84
  • 128
  • what is your goal ? why do want to detect this (perhaps there is some other way to achieve your goal) ? – Yahia Mar 02 '12 at 21:14
  • 5
    If it is running in IIS Express, what do you want to handle differently? Maybe that's the question you need to ask rather than how to detect IIS Express. "How do I do ____ instead of _____ when running in debug?," for example. – Anthony Pegram Mar 02 '12 at 21:15
  • The desire is centered around examining some configuration elements - using DirectoryEntry("IIS:/localhost/W3SVC/") vs. parsing the XML in applicationhost.config that controls IIS Express. – Goyuix Mar 02 '12 at 22:05
  • 1
    Again, what exactly is your goal? Why should the application be aware of the hosting environment? – John Saunders Mar 03 '12 at 04:53

4 Answers4

33

Would checking the current process name do the trick?

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

Normal IIS runs under w3wp.exe from memory.

Oran Dennison
  • 3,237
  • 1
  • 29
  • 37
Strelok
  • 50,229
  • 9
  • 102
  • 115
  • 1
    It's `w3wp` for IIS 7.5 -- but Im not sure about different versions of IIS. I know it's something different for the real old versions of IIS... – debracey Mar 07 '12 at 03:54
  • 1
    @debracey yes for older versions it will be `aspnet_wp.exe`. – Strelok Mar 07 '12 at 04:06
  • The only potential issue I have encountered with this approach is that the System.Diagnostics.Process class requires Full Trust. Otherwise is seems to be working like a charm. – Goyuix Mar 08 '12 at 15:56
  • 4
    I tested the code and should be changed to: bool isExpress = String.Compare(Process.GetCurrentProcess().ProcessName,"iisexpress") == 0; – Alex Pop May 07 '13 at 14:17
3

Oran Dennison's answer doesn't work for me any more with dotnet core.

I extended it by first creating a method that can get the parent process:

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

    }
}

Then, you can do something like:

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;
}
mheyman
  • 4,211
  • 37
  • 34
  • FYI `IWebHostBuilder.UseIIS()` (https://github.com/dotnet/aspnetcore/blob/c85baf8db0c72ae8e68643029d514b2e737c9fae/src/Servers/IIS/IIS/src/WebHostBuilderIISExtensions.cs#L31) checks if `aspnetcorev2_inprocess.dll` has been loaded in this process. – Jeremy Lakeman Jan 14 '22 at 03:43
2

If you don't mind dropping into COM level APIs, you could use the IIS Version Manager API

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

There is some discussion about how this has been used in this SO Post: Starting and stopping IIS Express programmatically -- not exactly what you want, but they do discuss using the API.

Edit: I should add that I haven't tried this myself but it seems promising, good luck!

Community
  • 1
  • 1
debracey
  • 6,517
  • 1
  • 30
  • 56
  • I looked into this API but I had two reservations: One it is flagged as "not intended to be used directly from your code" - not a deal breaker but not encouraging either. Two I am not sure how (or even if you can) connect the currently executing code to an instance returned from the API. Maybe by matching URLs or something. – Goyuix Mar 06 '12 at 15:50
  • Not sure what you're getting at -- but what I would do is pull the IIS version into your code (into your own managed `enum` maybe) when the application pool starts up, then just store that in a static variable -- don't go off querying the COM API every time. The server type obviously can't change without restarting your app. – debracey Mar 06 '12 at 18:17
  • If I new up the IISVersionManager class, I can get a listing of IIS instances available on the machine but I have no way of mapping that IISVersion interface to the code that is executing inside of an IIS instance. I really don't see how this COM API helps me know if code that is currently running is inside IIS Express or not - not just that IIS Express is available. Maybe a code sample would help clarify what you are suggesting? – Goyuix Mar 07 '12 at 00:48
  • Oh OK - yeah - that's an excellent point... back to the drawing board – debracey Mar 07 '12 at 03:54
2

Can we not try and see if one or more limitation of IIS Express works or not, if it works it is not IIS Express. Example IIS Express does not support sharepoint services

Rohit Sharma
  • 6,136
  • 3
  • 28
  • 47
  • Could you please share which of those specific (or other) limitations you think you could reliably test for? – Goyuix Mar 11 '12 at 19:59
  • some sort of query, say environment variables %IISBin% would be a good hint? or query share point service and if the result is unsupported-exception we know we are on IIS Express – Rohit Sharma Mar 13 '12 at 08:42
  • Testing for %IIS_BIN% may work, it looks like only IIS Express sets that variable. The only gotcha being that the EnvironmentPermission class can be set to deny access to those variables. I have no clue what you mean by "query for share point service" - SharePoint is a product you can install, not something native to IIS. – Goyuix Mar 13 '12 at 19:29