File: Configuration\serverconfig.cs
Project: ndp\fx\src\xsp\system\Web\System.Web.csproj (System.Web)
//------------------------------------------------------------------------------
// <copyright file="ServerConfig.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
 
namespace System.Web.Configuration {
 
    using System.Configuration;
    using System.Collections;
    using System.Collections.Generic;
    using System.Globalization;
    using System.Security;
    using System.Security.Permissions;
    using System.Text;
    using System.Threading;
    using System.Web.Util;
    using System.Web.Hosting;
    using System.Web.Caching;
    using System.Web.Compilation;
    using Microsoft.Win32;
 
    //
    // Abstracts differences between config retreived from IIS 6 metabase
    // and config retreived from new IIS7 configuration system.
    //
    static internal class ServerConfig {
 
        static int s_iisMajorVersion = 0;
 
        static object s_expressConfigsLock = new object();
 
        // used in the default domain only, by the ClientBuildManager
        static Dictionary<string, ExpressServerConfig> s_expressConfigs;
 
        static string s_iisExpressVersion;
 
        // used in non-default domains only, by the ClientBuildManager
        internal static string IISExpressVersion {
            get {
                return s_iisExpressVersion;
            }
            set {
                if (Thread.GetDomain().IsDefaultAppDomain() || (s_iisExpressVersion != null && s_iisExpressVersion != value ))
                    throw new InvalidOperationException();
                s_iisExpressVersion = value;
            }
        }
 
        internal static bool UseMetabase {
            get
            {
                // This property has been subtly twisted over the years to mean something close to, but not exactly
                // "Use Metabase". There are 4 distinct scenarios for server config systems now. 1) The old Metabase
                // for IIS6 and earlier. 2) The new native config reader for IIS7 and later. 3) A ProcessHost-based
                // config interface, where self-hosters can plug in their own server config system. And 4) Nothing.
 
                // In the case of scenario #4 though, we have to have something. By definition, scenario #4 means
                // there is no server config provided by the process host ala scenario #3. So we end up in
                // IISMapPath.GetInstance() to decide which IIS server config system to use. And this property is
                // largely responsible for that choice.  If IIS is installed, obviously we should choose the system
                // that matches the IIS version. If IIS is _not_ installed on the machine though, trying to use
                // the native config reader will result in unhandled exceptions, whereas the metabase system does
                // not. I don't believe this was a thought-out scenario when these init paths where defined. But in
                // the case of no IIS and no IISExpress, we have been using Metabase server config for a long long time,
                // and we should continue to do so for compat, even if it doesn't make logical sense.
 
                // See VSO #463596, #406378, #421116, #470016, and #889110.
 
                // If we detect IISExpress ==> Always use Native Config
                if (IISExpressVersion != null || HostingEnvironment.IsUnderIISExpressProcess) {
                    return false;
                }
 
                // Otherwise, check the IIS version.
                //    7 and above ==> Native Config
                //    6 and under, or NO IIS ==> Metabase
                if (s_iisMajorVersion == 0) {
                    int version;
                    try {
                        new RegistryPermission(RegistryPermissionAccess.Read, "HKEY_LOCAL_MACHINE\\Software\\Microsoft\\InetStp").Assert();
                        object ver = Registry.GetValue("HKEY_LOCAL_MACHINE\\Software\\Microsoft\\InetStp", "MajorVersion", 0);
                        version = (ver != null) ? (int)ver : -1;
                    }
                    catch (ArgumentException) {
                        // Ignore ArgumentException from Registry.GetValue. This may indicate that the key does not exist, i.e. IIS not installed
                        version = -1; // Key not found
                    }
                    Interlocked.CompareExchange(ref s_iisMajorVersion, version, 0);
                }
 
                return s_iisMajorVersion <= 6;
            }
        }
 
        static internal IServerConfig GetInstance() {
            // IIS 7 bits on <= IIS 6: use the metabase
            if (UseMetabase) {
                return MetabaseServerConfig.GetInstance();
            }
            if (IISExpressVersion == null) {
                return ProcessHostServerConfig.GetInstance();
            }
            return ExpressServerConfig.GetInstance(IISExpressVersion);
        }
 
        static internal IServerConfig GetDefaultDomainInstance(string version) {
            if (version == null) {
                return GetInstance();
            }
            ExpressServerConfig expressConfig = null;
            lock (s_expressConfigsLock) {
                if (s_expressConfigs == null) {
                    if (!Thread.GetDomain().IsDefaultAppDomain()) {
                        throw new InvalidOperationException();
                    }
                    s_expressConfigs = new Dictionary<string, ExpressServerConfig>(3);
                }
                if (!s_expressConfigs.TryGetValue(version, out expressConfig)) {
                    expressConfig = new ExpressServerConfig(version);
                    s_expressConfigs[version] = expressConfig;
                }
            }
            return expressConfig;
        }
 
        //
        // Return true in cases where web server configuration should be used
        // to resolve paths.
        //
        static int s_useServerConfig = -1;
        static internal bool UseServerConfig {
            get {
                if (s_useServerConfig == -1) {
                    int useServerConfig = 0;
                    // Must use web server config if there is no hosting environment
                    if (!HostingEnvironment.IsHosted) {
                        useServerConfig = 1;
                    }
                    // Hosting environment is the web server
                    else if (HostingEnvironment.ApplicationHostInternal is ISAPIApplicationHost) {
                        useServerConfig = 1;
                    }
                    // Hosting environment is the web server
                    else if (HostingEnvironment.IsUnderIISProcess && !BuildManagerHost.InClientBuildManager) {
                        useServerConfig = 1;
                    }
                    Interlocked.CompareExchange(ref s_useServerConfig, useServerConfig, -1);
                }
 
                return s_useServerConfig == 1;
            }
        }
 
    }
}