HealthMonitoringSectionHelper.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / whidbey / NetFxQFE / ndp / fx / src / xsp / System / Web / Configuration / HealthMonitoringSectionHelper.cs / 1 / HealthMonitoringSectionHelper.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

namespace System.Web.Configuration { 
    using System; 
    using System.Xml;
    using System.Configuration; 
    using System.Collections.Specialized;
    using System.Collections;
    using System.Globalization;
    using System.IO; 
    using System.Text;
    using System.ComponentModel; 
    using System.Web.Hosting; 
    using System.Web.Util;
    using System.Web.Configuration; 
    using System.Web.Management;
    using System.Web.Compilation;

    internal class HealthMonitoringSectionHelper { 
        static HealthMonitoringSectionHelper s_helper;
 
        static RuleInfoComparer s_ruleInfoComparer = new RuleInfoComparer(); 

        HealthMonitoringSection _section; 
        internal ProviderInstances _providerInstances;
        internal Hashtable _customEvaluatorInstances;
        internal ArrayList _ruleInfos;
        bool _enabled; 

        // Cached matched rules for system events.  For details, see comments for s_eventArrayDimensionSizes 
        // in WebEventCodes.cs 
        static ArrayList[,] _cachedMatchedRules;
 
#if DBG
        // Because we assume no two different event type will use the same event code, in debug mode
        // we use this hashtable to make sure our assumption is true.
        Hashtable                       _cachedTypeOfMatchedRulesSystem = new Hashtable(); 
#endif
 
        // Cached matched rules based on WebBaseEvent Hashcode, and is for non-system events. 
        Hashtable _cachedMatchedRulesForCustomEvents;
 
        static internal HealthMonitoringSectionHelper GetHelper() {
            if (s_helper == null) {
                s_helper = new HealthMonitoringSectionHelper();
            } 

            return s_helper; 
        } 

        HealthMonitoringSectionHelper() { 

            // Handle config exceptions so we can still log messages to the event log.
            try {
                _section = RuntimeConfig.GetAppConfig().HealthMonitoring; 
            }
            catch(Exception e) { 
                // If InitializationException has not already been set, then this exception 
                // is happening because the  section has an error.
                // By setting InitializationException, we allow the exception to be displayed in the response. 
                // If InitializationException is already set, ignore this exception so we can
                // display the original in the response.
                if (HttpRuntime.InitializationException == null) {
                    HttpRuntime.InitializationException = e; 
                }
                _section = RuntimeConfig.GetAppLKGConfig().HealthMonitoring; 
                // WOS 1965670: if we fail to get the section throw the previous error 
                if (_section == null) {
                    throw; 
                }
            }

            _enabled = _section.Enabled; 

            if (!_enabled) { 
                return; 
            }
 
            // First run some basic sanity check
            BasicSanityCheck();

            // Init some class members 
            _ruleInfos = new ArrayList();
            _customEvaluatorInstances = new Hashtable(); 
            _providerInstances = new ProviderInstances(_section); 
            _cachedMatchedRulesForCustomEvents = new Hashtable(new WebBaseEventKeyComparer());
            _cachedMatchedRules = new ArrayList[WebEventCodes.GetEventArrayDimensionSize(0), 
                                                        WebEventCodes.GetEventArrayDimensionSize(1)];

            BuildRuleInfos();
 
            _providerInstances.CleanupUninitProviders();
        } 
 
        internal bool Enabled {
            get { return _enabled; } 
        }

        internal HealthMonitoringSection HealthMonitoringSection {
            get { return _section; } 
        }
 
        void BasicSanityCheck() { 
            Type type;
 
            foreach (ProviderSettings providerSettings in _section.Providers) {
                // Make sure the type is valid.
                type = ConfigUtil.GetType(providerSettings.Type, "type", providerSettings);
 
                // Make sure the type support WebEventProvider
                HandlerBase.CheckAssignableType(providerSettings.ElementInformation.Properties["type"].Source, 
                        providerSettings.ElementInformation.Properties["type"].LineNumber, 
                        typeof(WebEventProvider), type);
 
            }

            foreach (EventMappingSettings eventMappingSettings in _section.EventMappings) {
                // Make sure the type is valid. 
                type = ConfigUtil.GetType(eventMappingSettings.Type, "type", eventMappingSettings);
 
                // Make sure startEventCode <= endEventCode 
                if (!(eventMappingSettings.StartEventCode <= eventMappingSettings.EndEventCode)) {
                    string attribute; 

                    // We don't know which one was specified unless we test it
                    attribute = "startEventCode";
                    if (eventMappingSettings.ElementInformation.Properties[attribute].LineNumber == 0) { 
                        attribute = "endEventCode";
                        Debug.Assert(eventMappingSettings.ElementInformation.Properties[attribute].LineNumber != 0, 
                                    "eventMappingSettings.ElementInformation.Properties[attribute].LineNumber != 0"); 
                    }
 
                    throw new ConfigurationErrorsException(
                        SR.GetString(SR.Event_name_invalid_code_range),
                        eventMappingSettings.ElementInformation.Properties[attribute].Source, eventMappingSettings.ElementInformation.Properties[attribute].LineNumber);
                } 

                // Make sure the type support WebBaseEvent 
                HandlerBase.CheckAssignableType(eventMappingSettings.ElementInformation.Properties["type"].Source, 
                            eventMappingSettings.ElementInformation.Properties["type"].LineNumber,
                            typeof(System.Web.Management.WebBaseEvent), type); 

                // It's a valid type.  Might as well save it.
                eventMappingSettings.RealType = type;
            } 

            foreach (RuleSettings rule in _section.Rules) { 
 
                // Go thru all the Rules, and make sure all referenced provider, eventName
                // and profile exist. 

                string provider = rule.Provider;
                if (!String.IsNullOrEmpty(provider)) {
                    ProviderSettings providerSettings = _section.Providers[provider]; 
                    if (providerSettings == null) {
                        throw new ConfigurationErrorsException( 
                            SR.GetString(SR.Health_mon_provider_not_found, provider), 
                                rule.ElementInformation.Properties["provider"].Source,
                                rule.ElementInformation.Properties["provider"].LineNumber); 
                    }
                }

                string profile = rule.Profile; 
                if (!String.IsNullOrEmpty(profile)) {
                    if (_section.Profiles[profile] == null) { 
                        throw new ConfigurationErrorsException( 
                            SR.GetString(SR.Health_mon_profile_not_found, profile),
                                rule.ElementInformation.Properties["profile"].Source, 
                                rule.ElementInformation.Properties["profile"].LineNumber);
                    }
                }
 
                if (_section.EventMappings[rule.EventName] == null) {
                    throw new ConfigurationErrorsException( 
                        SR.GetString(SR.Event_name_not_found, rule.EventName), 
                            rule.ElementInformation.Properties["eventName"].Source, rule.ElementInformation.Properties["eventName"].LineNumber);
                } 

            }
        }
 
        void DisplayRuleInfo(RuleInfo ruleInfo) {
#if DEBUG 
            Debug.Trace("BuildRuleInfos", "====================== Rule Info ======================="); 
            Debug.Trace("BuildRuleInfos", "name:" + ruleInfo._ruleSettings.Name);
            Debug.Trace("BuildRuleInfos", "type:" + ruleInfo._eventMappingSettings.RealType.Name); 
            Debug.Trace("BuildRuleInfos", "minInstances:" + ruleInfo._minInstances);
            Debug.Trace("BuildRuleInfos", "maxLimit:" + ruleInfo._maxLimit);
            Debug.Trace("BuildRuleInfos", "minInterval:" + ruleInfo._minInterval);
            Debug.Trace("BuildRuleInfos", "provider:" + ruleInfo._ruleSettings.Provider); 
            Debug.Trace("BuildRuleInfos", "referenced provider:" + (ruleInfo._referencedProvider == null ? String.Empty : ruleInfo._referencedProvider.GetType().Name));
            Debug.Trace("BuildRuleInfos", "========================================================="); 
#endif 
        }
 
        void BuildRuleInfos() {
            Debug.Trace("BuildRuleInfos", "BuildRuleInfos called");

            // Each ruleInfo is an object that takes the information 
            // stored in a ruleSettings and merge it with values from profileSettings.
 
            // At the end, we'll sort the rules based on type (most specific type last) 

            foreach (RuleSettings ruleSettings in _section.Rules) { 
                RuleInfo ruleInfo = CreateRuleInfo(ruleSettings);
                DisplayRuleInfo(ruleInfo);
                _ruleInfos.Add(ruleInfo);
            } 

            _ruleInfos.Sort(s_ruleInfoComparer); 
        } 

        RuleInfo CreateRuleInfo(RuleSettings ruleSettings) { 
            RuleInfo ruleInfo = new RuleInfo(ruleSettings, _section);

            // Inherit values from profile
            MergeValuesWithProfile(ruleInfo); 

            // Find out which provider it's referencing 
            InitReferencedProvider(ruleInfo); 

            // Initialize the cutom evaluator type 
            InitCustomEvaluator(ruleInfo);

            return ruleInfo;
        } 

        void InitReferencedProvider(RuleInfo ruleInfo) { 
            String providerName; 
            WebEventProvider provider;
 
            Debug.Assert(ruleInfo._referencedProvider == null, "ruleInfo._referencedProvider == null");

            providerName = ruleInfo._ruleSettings.Provider;
            if (String.IsNullOrEmpty(providerName)) { 
                return;
            } 
 
            provider = _providerInstances[providerName];
            Debug.Assert(provider != null, "provider != null"); 

            ruleInfo._referencedProvider = provider;
        }
 
        void MergeValuesWithProfile(RuleInfo ruleInfo) {
            ProfileSettings profileSettings = null; 
 
            if (ruleInfo._ruleSettings.ElementInformation.Properties["profile"].ValueOrigin != PropertyValueOrigin.Default) {
                profileSettings = _section.Profiles[ruleInfo._ruleSettings.Profile]; 
                Debug.Assert(profileSettings != null, "profileSettings != null");
            }

            if (profileSettings != null && ruleInfo._ruleSettings.ElementInformation.Properties["minInstances"].ValueOrigin == PropertyValueOrigin.Default) { 
                ruleInfo._minInstances = profileSettings.MinInstances;
            } 
            else { 
                ruleInfo._minInstances = ruleInfo._ruleSettings.MinInstances;
            } 

            if (profileSettings != null && ruleInfo._ruleSettings.ElementInformation.Properties["maxLimit"].ValueOrigin == PropertyValueOrigin.Default) {
                ruleInfo._maxLimit = profileSettings.MaxLimit;
            } 
            else {
                ruleInfo._maxLimit = ruleInfo._ruleSettings.MaxLimit; 
            } 

            if (profileSettings != null && ruleInfo._ruleSettings.ElementInformation.Properties["minInterval"].ValueOrigin == PropertyValueOrigin.Default) { 
                ruleInfo._minInterval = profileSettings.MinInterval;
            }
            else {
                ruleInfo._minInterval = ruleInfo._ruleSettings.MinInterval; 
            }
 
            if (profileSettings != null && ruleInfo._ruleSettings.ElementInformation.Properties["custom"].ValueOrigin == PropertyValueOrigin.Default) { 
                ruleInfo._customEvaluator = profileSettings.Custom;
                ruleInfo._customEvaluatorConfig = profileSettings; 
            }
            else {
                ruleInfo._customEvaluator = ruleInfo._ruleSettings.Custom;
                ruleInfo._customEvaluatorConfig = ruleInfo._ruleSettings; 
            }
        } 
 
        void InitCustomEvaluator(RuleInfo ruleInfo) {
            string customEvaluator = ruleInfo._customEvaluator; 

            if (customEvaluator == null ||
                customEvaluator.Trim().Length == 0) {
                ruleInfo._customEvaluatorType = null; 
                return;
            } 
 
            ruleInfo._customEvaluatorType = ConfigUtil.GetType(ruleInfo._customEvaluator,
                "custom", ruleInfo._customEvaluatorConfig); 

            // Make sure the type support WebBaseEvent
            HandlerBase.CheckAssignableType(ruleInfo._customEvaluatorConfig.ElementInformation.Properties["custom"].Source,
                    ruleInfo._customEvaluatorConfig.ElementInformation.Properties["custom"].LineNumber, 
                    typeof(System.Web.Management.IWebEventCustomEvaluator), ruleInfo._customEvaluatorType);
 
            // Create a public instance of the custom evaluator 
            if (_customEvaluatorInstances[ruleInfo._customEvaluatorType] == null) {
                _customEvaluatorInstances[ruleInfo._customEvaluatorType] = HttpRuntime.CreatePublicInstance(ruleInfo._customEvaluatorType); 
            }
        }

        // Find the corresponding array of RuleInfo based on the fired event 
        internal ArrayList FindFiringRuleInfos(Type eventType, int eventCode) {
            ArrayList foundFiringRuleInfos; 
            bool systemEvent = eventCode < WebEventCodes.WebExtendedBase; 
            CustomWebEventKey customWebEventKey = null;
            object lockObject; 
            int index0 = 0, index1 = 0;

#if DBG
            if (systemEvent) { 
                Type    type;
 
                type = (Type)_cachedTypeOfMatchedRulesSystem[eventCode]; 
                if (type == null) {
                    lock(_cachedTypeOfMatchedRulesSystem) { 
                        type = (Type)_cachedTypeOfMatchedRulesSystem[eventCode];
                        if (type == null) {
                            _cachedTypeOfMatchedRulesSystem[eventCode] = eventType;
                        } 
                    }
                } 
 
                if (type != null) {
                    Debug.Assert(type == eventType, 
                        "For system events, we assume each event code will map only to one event type. " +
                        "Eventcode= " + eventCode + "; stored type= " + type.ToString() +
                        "; raised event type= " + eventType);
                } 
            }
#endif 
 
            // First, we look at the cache to see if we find the array.
            if (systemEvent) { 
                WebEventCodes.GetEventArrayIndexsFromEventCode(eventCode, out index0, out index1);
                foundFiringRuleInfos = _cachedMatchedRules[index0, index1];
            }
            else { 
                customWebEventKey = new CustomWebEventKey(eventType, eventCode);
                foundFiringRuleInfos = (ArrayList)_cachedMatchedRulesForCustomEvents[customWebEventKey]; 
            } 

            if (foundFiringRuleInfos != null) { 
                return foundFiringRuleInfos;
            }

            if (systemEvent) { 
                lockObject = _cachedMatchedRules;
            } 
            else { 
                lockObject = _cachedMatchedRulesForCustomEvents;
            } 

            lock (lockObject) {

                if (systemEvent) { 
                    foundFiringRuleInfos = _cachedMatchedRules[index0, index1];
                } 
                else { 
                    Debug.Assert(customWebEventKey != null);
                    foundFiringRuleInfos = (ArrayList)_cachedMatchedRulesForCustomEvents[customWebEventKey]; 
                }

                if (foundFiringRuleInfos != null) {
                    return foundFiringRuleInfos; 
                }
 
                // Not found in cache. 

                ArrayList matchedRules = new ArrayList(); 

                // Go thru the sorted ruleInfo array and look for matching ruleInfo,
                // starting from the most specific type.
                for (int i = _ruleInfos.Count - 1; i >= 0; i--) { 
                    RuleInfo curRule = (RuleInfo)_ruleInfos[i];
 
                    // Now see if the current rule matches the raised event 
                    if (curRule.Match(eventType, eventCode)) {
                        matchedRules.Add(new FiringRuleInfo(curRule)); 
                    }
                }

                // Then for each matched rule, we need to figure out if the provider it 
                // uses is also used by other rules.  We need this info because if multiple rules are
                // using the same provider, we fire the event to the provider only once. 
                int count = matchedRules.Count; 
                for (int i = 0; i < count; i++) {
                    FiringRuleInfo info1 = (FiringRuleInfo)matchedRules[i]; 

                    if (info1._ruleInfo._referencedProvider != null) {
                        for (int j = i + 1; j < count; j++) {
 
                            FiringRuleInfo info2 = (FiringRuleInfo)matchedRules[j];
                            if (info2._ruleInfo._referencedProvider != null &&    // ignore null-provider 
                                info2._indexOfFirstRuleInfoWithSameProvider == -1 &&  // ignore rules that were marked already 
                                info1._ruleInfo._referencedProvider == info2._ruleInfo._referencedProvider) {   // they are pointing to the same provider
 
                                // We'll remember the index of the first rule info that share the same
                                // provider. For details on how this index is used, please see
                                // WebBaseEvent.RaiseInternal.
                                if (info1._indexOfFirstRuleInfoWithSameProvider == -1) { 
                                    info1._indexOfFirstRuleInfoWithSameProvider = i;
                                } 
 
                                info2._indexOfFirstRuleInfoWithSameProvider = i;
 
                            }
                        }
                    }
                } 

 
#if DBG 
                Debug.Trace("FindRuleInfos", "------------------------------------------------");
                Debug.Trace("FindRuleInfos", "Find ruleInfos for event with type=" + eventType.ToString() + 
                    ", EventCode=" + eventCode);

                foreach(FiringRuleInfo info in matchedRules) {
                    Debug.Trace("FindRuleInfos", "Provider=" + info._ruleInfo._ruleSettings.Provider + 
                        "; eventNameType=" + info._ruleInfo._eventMappingSettings.RealType.ToString() +
                        "; _indexOfFirstRuleInfoWithSameProvider=" + info._indexOfFirstRuleInfoWithSameProvider); 
                } 
                Debug.Trace("FindRuleInfos", "------------------------------------------------");
#endif 

                // save matchedRules in the cache
                if (systemEvent) {
                    _cachedMatchedRules[index0, index1] = matchedRules; 
                }
                else { 
                    Debug.Assert(customWebEventKey != null); 
                    _cachedMatchedRulesForCustomEvents[customWebEventKey] = matchedRules;
                } 

                return matchedRules;
            }
        } 

        internal class RuleInfo { 
            internal string _customEvaluator; 
            internal ConfigurationElement _customEvaluatorConfig;
 
            // The following properties are cached here for performance reason
            internal int _minInstances;
            internal int _maxLimit;
            internal TimeSpan _minInterval;   // in seconds 

            internal RuleSettings _ruleSettings; 
 
            internal WebEventProvider _referencedProvider;
 
            internal Type _customEvaluatorType;

            internal EventMappingSettings _eventMappingSettings;
 
            internal RuleFiringRecord _ruleFiringRecord;
 
            internal RuleInfo(RuleSettings ruleSettings, HealthMonitoringSection section) { 
                _eventMappingSettings = section.EventMappings[ruleSettings.EventName];
 
                _ruleSettings = ruleSettings;
                _ruleFiringRecord = new RuleFiringRecord(this);
            }
 
            internal bool Match(Type eventType, int eventCode) {
                // Fail if the type doesn't match. 
                if (!(eventType.Equals(_eventMappingSettings.RealType) || 
                       eventType.IsSubclassOf(_eventMappingSettings.RealType))) {
                    return false; 
                }

                // Fail if the event code doesn't match
                if (!(_eventMappingSettings.StartEventCode <= eventCode && 
                        eventCode <= _eventMappingSettings.EndEventCode)) {
                    return false; 
                } 

                return true; 
            }
        }

        internal class FiringRuleInfo { 
            internal RuleInfo _ruleInfo;
            internal int _indexOfFirstRuleInfoWithSameProvider; 
 
            internal FiringRuleInfo(RuleInfo ruleInfo) {
                _ruleInfo = ruleInfo; 
                _indexOfFirstRuleInfoWithSameProvider = -1;
            }
        }
 
        internal class ProviderInstances {
            internal Hashtable _instances; // case-insensitive because the providers collection is too. 
 
            internal ProviderInstances(HealthMonitoringSection section) {
                // Build the array of providers 
                // Don't create an instance yet, but only store the providerInfo in the HashTable.
                _instances = CollectionsUtil.CreateCaseInsensitiveHashtable(section.Providers.Count);

                foreach (object obj in section.Providers) { 
                    ProviderSettings settings = (ProviderSettings)obj;
 
                    // Please note we are storing the ProviderSettings in the hashtable. 
                    // But if we create an instance of that provider, we will replace
                    // that string with a provider object. 
                    _instances.Add(settings.Name, settings);
                }
            }
 
            WebEventProvider GetProviderInstance(string providerName) {
                WebEventProvider provider; 
                object o; 

                o = _instances[providerName]; 
                if (o == null) {
                    return null;
                }
 
                ProviderSettings providerSettings = o as ProviderSettings;
 
                if (providerSettings != null) { 
                    // If what we got is still a ProviderSettings, it means we haven't created an instance
                    // of it yet. 
                    Type type;
                    string typeName = providerSettings.Type;

                    type = BuildManager.GetType(typeName, false); 
                    Debug.Assert(type != null, "type != null");
 
                    if (typeof(IInternalWebEventProvider).IsAssignableFrom(type)) { 
                        provider = (WebEventProvider)HttpRuntime.CreateNonPublicInstance(type);
                    } 
                    else {
                        provider = (WebEventProvider)HttpRuntime.CreatePublicInstance(type);
                    }
 
                    using (new ProcessImpersonationContext()) {
                        try { 
                            provider.Initialize(providerSettings.Name, providerSettings.Parameters); 
                        }
                        catch (ConfigurationErrorsException) { 
                            throw;
                        }
                        catch (ConfigurationException e) {
                            throw new ConfigurationErrorsException(e.Message, providerSettings.ElementInformation.Properties["type"].Source, 
                                providerSettings.ElementInformation.Properties["type"].LineNumber);
                        } 
                        catch { 
                            throw;
                        } 
                    }

                    Debug.Trace("ProviderInstances", "Create a provider instance: " +
                        "name=" + providerSettings.Name + ";type=" + typeName); 

                    _instances[providerName] = provider; 
                } 
                else {
                    provider = o as WebEventProvider; 
                    Debug.Assert(provider != null, "provider != null");
                }

                return provider; 
            }
 
            internal WebEventProvider this[String name] { 
                get {
                    return GetProviderInstance(name); 
                }
            }

            // Cleanup each provider for which we have NOT created an instance. 
            internal void CleanupUninitProviders() {
                ArrayList list = new ArrayList(); 
 
                foreach (DictionaryEntry de in _instances) {
                    if (de.Value is ProviderSettings) { 
                        list.Add(de.Key);
                    }
                }
 
                foreach (object o in list) {
                    Debug.Trace("ProviderInstances", "Remove " + (string)o + " from providers"); 
                    _instances.Remove(o); 
                }
            } 

            internal bool ContainsKey(string name) {
                return _instances.ContainsKey(name);
            } 

            public IDictionaryEnumerator GetEnumerator() { 
                return _instances.GetEnumerator(); 
            }
        } 
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

namespace System.Web.Configuration { 
    using System; 
    using System.Xml;
    using System.Configuration; 
    using System.Collections.Specialized;
    using System.Collections;
    using System.Globalization;
    using System.IO; 
    using System.Text;
    using System.ComponentModel; 
    using System.Web.Hosting; 
    using System.Web.Util;
    using System.Web.Configuration; 
    using System.Web.Management;
    using System.Web.Compilation;

    internal class HealthMonitoringSectionHelper { 
        static HealthMonitoringSectionHelper s_helper;
 
        static RuleInfoComparer s_ruleInfoComparer = new RuleInfoComparer(); 

        HealthMonitoringSection _section; 
        internal ProviderInstances _providerInstances;
        internal Hashtable _customEvaluatorInstances;
        internal ArrayList _ruleInfos;
        bool _enabled; 

        // Cached matched rules for system events.  For details, see comments for s_eventArrayDimensionSizes 
        // in WebEventCodes.cs 
        static ArrayList[,] _cachedMatchedRules;
 
#if DBG
        // Because we assume no two different event type will use the same event code, in debug mode
        // we use this hashtable to make sure our assumption is true.
        Hashtable                       _cachedTypeOfMatchedRulesSystem = new Hashtable(); 
#endif
 
        // Cached matched rules based on WebBaseEvent Hashcode, and is for non-system events. 
        Hashtable _cachedMatchedRulesForCustomEvents;
 
        static internal HealthMonitoringSectionHelper GetHelper() {
            if (s_helper == null) {
                s_helper = new HealthMonitoringSectionHelper();
            } 

            return s_helper; 
        } 

        HealthMonitoringSectionHelper() { 

            // Handle config exceptions so we can still log messages to the event log.
            try {
                _section = RuntimeConfig.GetAppConfig().HealthMonitoring; 
            }
            catch(Exception e) { 
                // If InitializationException has not already been set, then this exception 
                // is happening because the  section has an error.
                // By setting InitializationException, we allow the exception to be displayed in the response. 
                // If InitializationException is already set, ignore this exception so we can
                // display the original in the response.
                if (HttpRuntime.InitializationException == null) {
                    HttpRuntime.InitializationException = e; 
                }
                _section = RuntimeConfig.GetAppLKGConfig().HealthMonitoring; 
                // WOS 1965670: if we fail to get the section throw the previous error 
                if (_section == null) {
                    throw; 
                }
            }

            _enabled = _section.Enabled; 

            if (!_enabled) { 
                return; 
            }
 
            // First run some basic sanity check
            BasicSanityCheck();

            // Init some class members 
            _ruleInfos = new ArrayList();
            _customEvaluatorInstances = new Hashtable(); 
            _providerInstances = new ProviderInstances(_section); 
            _cachedMatchedRulesForCustomEvents = new Hashtable(new WebBaseEventKeyComparer());
            _cachedMatchedRules = new ArrayList[WebEventCodes.GetEventArrayDimensionSize(0), 
                                                        WebEventCodes.GetEventArrayDimensionSize(1)];

            BuildRuleInfos();
 
            _providerInstances.CleanupUninitProviders();
        } 
 
        internal bool Enabled {
            get { return _enabled; } 
        }

        internal HealthMonitoringSection HealthMonitoringSection {
            get { return _section; } 
        }
 
        void BasicSanityCheck() { 
            Type type;
 
            foreach (ProviderSettings providerSettings in _section.Providers) {
                // Make sure the type is valid.
                type = ConfigUtil.GetType(providerSettings.Type, "type", providerSettings);
 
                // Make sure the type support WebEventProvider
                HandlerBase.CheckAssignableType(providerSettings.ElementInformation.Properties["type"].Source, 
                        providerSettings.ElementInformation.Properties["type"].LineNumber, 
                        typeof(WebEventProvider), type);
 
            }

            foreach (EventMappingSettings eventMappingSettings in _section.EventMappings) {
                // Make sure the type is valid. 
                type = ConfigUtil.GetType(eventMappingSettings.Type, "type", eventMappingSettings);
 
                // Make sure startEventCode <= endEventCode 
                if (!(eventMappingSettings.StartEventCode <= eventMappingSettings.EndEventCode)) {
                    string attribute; 

                    // We don't know which one was specified unless we test it
                    attribute = "startEventCode";
                    if (eventMappingSettings.ElementInformation.Properties[attribute].LineNumber == 0) { 
                        attribute = "endEventCode";
                        Debug.Assert(eventMappingSettings.ElementInformation.Properties[attribute].LineNumber != 0, 
                                    "eventMappingSettings.ElementInformation.Properties[attribute].LineNumber != 0"); 
                    }
 
                    throw new ConfigurationErrorsException(
                        SR.GetString(SR.Event_name_invalid_code_range),
                        eventMappingSettings.ElementInformation.Properties[attribute].Source, eventMappingSettings.ElementInformation.Properties[attribute].LineNumber);
                } 

                // Make sure the type support WebBaseEvent 
                HandlerBase.CheckAssignableType(eventMappingSettings.ElementInformation.Properties["type"].Source, 
                            eventMappingSettings.ElementInformation.Properties["type"].LineNumber,
                            typeof(System.Web.Management.WebBaseEvent), type); 

                // It's a valid type.  Might as well save it.
                eventMappingSettings.RealType = type;
            } 

            foreach (RuleSettings rule in _section.Rules) { 
 
                // Go thru all the Rules, and make sure all referenced provider, eventName
                // and profile exist. 

                string provider = rule.Provider;
                if (!String.IsNullOrEmpty(provider)) {
                    ProviderSettings providerSettings = _section.Providers[provider]; 
                    if (providerSettings == null) {
                        throw new ConfigurationErrorsException( 
                            SR.GetString(SR.Health_mon_provider_not_found, provider), 
                                rule.ElementInformation.Properties["provider"].Source,
                                rule.ElementInformation.Properties["provider"].LineNumber); 
                    }
                }

                string profile = rule.Profile; 
                if (!String.IsNullOrEmpty(profile)) {
                    if (_section.Profiles[profile] == null) { 
                        throw new ConfigurationErrorsException( 
                            SR.GetString(SR.Health_mon_profile_not_found, profile),
                                rule.ElementInformation.Properties["profile"].Source, 
                                rule.ElementInformation.Properties["profile"].LineNumber);
                    }
                }
 
                if (_section.EventMappings[rule.EventName] == null) {
                    throw new ConfigurationErrorsException( 
                        SR.GetString(SR.Event_name_not_found, rule.EventName), 
                            rule.ElementInformation.Properties["eventName"].Source, rule.ElementInformation.Properties["eventName"].LineNumber);
                } 

            }
        }
 
        void DisplayRuleInfo(RuleInfo ruleInfo) {
#if DEBUG 
            Debug.Trace("BuildRuleInfos", "====================== Rule Info ======================="); 
            Debug.Trace("BuildRuleInfos", "name:" + ruleInfo._ruleSettings.Name);
            Debug.Trace("BuildRuleInfos", "type:" + ruleInfo._eventMappingSettings.RealType.Name); 
            Debug.Trace("BuildRuleInfos", "minInstances:" + ruleInfo._minInstances);
            Debug.Trace("BuildRuleInfos", "maxLimit:" + ruleInfo._maxLimit);
            Debug.Trace("BuildRuleInfos", "minInterval:" + ruleInfo._minInterval);
            Debug.Trace("BuildRuleInfos", "provider:" + ruleInfo._ruleSettings.Provider); 
            Debug.Trace("BuildRuleInfos", "referenced provider:" + (ruleInfo._referencedProvider == null ? String.Empty : ruleInfo._referencedProvider.GetType().Name));
            Debug.Trace("BuildRuleInfos", "========================================================="); 
#endif 
        }
 
        void BuildRuleInfos() {
            Debug.Trace("BuildRuleInfos", "BuildRuleInfos called");

            // Each ruleInfo is an object that takes the information 
            // stored in a ruleSettings and merge it with values from profileSettings.
 
            // At the end, we'll sort the rules based on type (most specific type last) 

            foreach (RuleSettings ruleSettings in _section.Rules) { 
                RuleInfo ruleInfo = CreateRuleInfo(ruleSettings);
                DisplayRuleInfo(ruleInfo);
                _ruleInfos.Add(ruleInfo);
            } 

            _ruleInfos.Sort(s_ruleInfoComparer); 
        } 

        RuleInfo CreateRuleInfo(RuleSettings ruleSettings) { 
            RuleInfo ruleInfo = new RuleInfo(ruleSettings, _section);

            // Inherit values from profile
            MergeValuesWithProfile(ruleInfo); 

            // Find out which provider it's referencing 
            InitReferencedProvider(ruleInfo); 

            // Initialize the cutom evaluator type 
            InitCustomEvaluator(ruleInfo);

            return ruleInfo;
        } 

        void InitReferencedProvider(RuleInfo ruleInfo) { 
            String providerName; 
            WebEventProvider provider;
 
            Debug.Assert(ruleInfo._referencedProvider == null, "ruleInfo._referencedProvider == null");

            providerName = ruleInfo._ruleSettings.Provider;
            if (String.IsNullOrEmpty(providerName)) { 
                return;
            } 
 
            provider = _providerInstances[providerName];
            Debug.Assert(provider != null, "provider != null"); 

            ruleInfo._referencedProvider = provider;
        }
 
        void MergeValuesWithProfile(RuleInfo ruleInfo) {
            ProfileSettings profileSettings = null; 
 
            if (ruleInfo._ruleSettings.ElementInformation.Properties["profile"].ValueOrigin != PropertyValueOrigin.Default) {
                profileSettings = _section.Profiles[ruleInfo._ruleSettings.Profile]; 
                Debug.Assert(profileSettings != null, "profileSettings != null");
            }

            if (profileSettings != null && ruleInfo._ruleSettings.ElementInformation.Properties["minInstances"].ValueOrigin == PropertyValueOrigin.Default) { 
                ruleInfo._minInstances = profileSettings.MinInstances;
            } 
            else { 
                ruleInfo._minInstances = ruleInfo._ruleSettings.MinInstances;
            } 

            if (profileSettings != null && ruleInfo._ruleSettings.ElementInformation.Properties["maxLimit"].ValueOrigin == PropertyValueOrigin.Default) {
                ruleInfo._maxLimit = profileSettings.MaxLimit;
            } 
            else {
                ruleInfo._maxLimit = ruleInfo._ruleSettings.MaxLimit; 
            } 

            if (profileSettings != null && ruleInfo._ruleSettings.ElementInformation.Properties["minInterval"].ValueOrigin == PropertyValueOrigin.Default) { 
                ruleInfo._minInterval = profileSettings.MinInterval;
            }
            else {
                ruleInfo._minInterval = ruleInfo._ruleSettings.MinInterval; 
            }
 
            if (profileSettings != null && ruleInfo._ruleSettings.ElementInformation.Properties["custom"].ValueOrigin == PropertyValueOrigin.Default) { 
                ruleInfo._customEvaluator = profileSettings.Custom;
                ruleInfo._customEvaluatorConfig = profileSettings; 
            }
            else {
                ruleInfo._customEvaluator = ruleInfo._ruleSettings.Custom;
                ruleInfo._customEvaluatorConfig = ruleInfo._ruleSettings; 
            }
        } 
 
        void InitCustomEvaluator(RuleInfo ruleInfo) {
            string customEvaluator = ruleInfo._customEvaluator; 

            if (customEvaluator == null ||
                customEvaluator.Trim().Length == 0) {
                ruleInfo._customEvaluatorType = null; 
                return;
            } 
 
            ruleInfo._customEvaluatorType = ConfigUtil.GetType(ruleInfo._customEvaluator,
                "custom", ruleInfo._customEvaluatorConfig); 

            // Make sure the type support WebBaseEvent
            HandlerBase.CheckAssignableType(ruleInfo._customEvaluatorConfig.ElementInformation.Properties["custom"].Source,
                    ruleInfo._customEvaluatorConfig.ElementInformation.Properties["custom"].LineNumber, 
                    typeof(System.Web.Management.IWebEventCustomEvaluator), ruleInfo._customEvaluatorType);
 
            // Create a public instance of the custom evaluator 
            if (_customEvaluatorInstances[ruleInfo._customEvaluatorType] == null) {
                _customEvaluatorInstances[ruleInfo._customEvaluatorType] = HttpRuntime.CreatePublicInstance(ruleInfo._customEvaluatorType); 
            }
        }

        // Find the corresponding array of RuleInfo based on the fired event 
        internal ArrayList FindFiringRuleInfos(Type eventType, int eventCode) {
            ArrayList foundFiringRuleInfos; 
            bool systemEvent = eventCode < WebEventCodes.WebExtendedBase; 
            CustomWebEventKey customWebEventKey = null;
            object lockObject; 
            int index0 = 0, index1 = 0;

#if DBG
            if (systemEvent) { 
                Type    type;
 
                type = (Type)_cachedTypeOfMatchedRulesSystem[eventCode]; 
                if (type == null) {
                    lock(_cachedTypeOfMatchedRulesSystem) { 
                        type = (Type)_cachedTypeOfMatchedRulesSystem[eventCode];
                        if (type == null) {
                            _cachedTypeOfMatchedRulesSystem[eventCode] = eventType;
                        } 
                    }
                } 
 
                if (type != null) {
                    Debug.Assert(type == eventType, 
                        "For system events, we assume each event code will map only to one event type. " +
                        "Eventcode= " + eventCode + "; stored type= " + type.ToString() +
                        "; raised event type= " + eventType);
                } 
            }
#endif 
 
            // First, we look at the cache to see if we find the array.
            if (systemEvent) { 
                WebEventCodes.GetEventArrayIndexsFromEventCode(eventCode, out index0, out index1);
                foundFiringRuleInfos = _cachedMatchedRules[index0, index1];
            }
            else { 
                customWebEventKey = new CustomWebEventKey(eventType, eventCode);
                foundFiringRuleInfos = (ArrayList)_cachedMatchedRulesForCustomEvents[customWebEventKey]; 
            } 

            if (foundFiringRuleInfos != null) { 
                return foundFiringRuleInfos;
            }

            if (systemEvent) { 
                lockObject = _cachedMatchedRules;
            } 
            else { 
                lockObject = _cachedMatchedRulesForCustomEvents;
            } 

            lock (lockObject) {

                if (systemEvent) { 
                    foundFiringRuleInfos = _cachedMatchedRules[index0, index1];
                } 
                else { 
                    Debug.Assert(customWebEventKey != null);
                    foundFiringRuleInfos = (ArrayList)_cachedMatchedRulesForCustomEvents[customWebEventKey]; 
                }

                if (foundFiringRuleInfos != null) {
                    return foundFiringRuleInfos; 
                }
 
                // Not found in cache. 

                ArrayList matchedRules = new ArrayList(); 

                // Go thru the sorted ruleInfo array and look for matching ruleInfo,
                // starting from the most specific type.
                for (int i = _ruleInfos.Count - 1; i >= 0; i--) { 
                    RuleInfo curRule = (RuleInfo)_ruleInfos[i];
 
                    // Now see if the current rule matches the raised event 
                    if (curRule.Match(eventType, eventCode)) {
                        matchedRules.Add(new FiringRuleInfo(curRule)); 
                    }
                }

                // Then for each matched rule, we need to figure out if the provider it 
                // uses is also used by other rules.  We need this info because if multiple rules are
                // using the same provider, we fire the event to the provider only once. 
                int count = matchedRules.Count; 
                for (int i = 0; i < count; i++) {
                    FiringRuleInfo info1 = (FiringRuleInfo)matchedRules[i]; 

                    if (info1._ruleInfo._referencedProvider != null) {
                        for (int j = i + 1; j < count; j++) {
 
                            FiringRuleInfo info2 = (FiringRuleInfo)matchedRules[j];
                            if (info2._ruleInfo._referencedProvider != null &&    // ignore null-provider 
                                info2._indexOfFirstRuleInfoWithSameProvider == -1 &&  // ignore rules that were marked already 
                                info1._ruleInfo._referencedProvider == info2._ruleInfo._referencedProvider) {   // they are pointing to the same provider
 
                                // We'll remember the index of the first rule info that share the same
                                // provider. For details on how this index is used, please see
                                // WebBaseEvent.RaiseInternal.
                                if (info1._indexOfFirstRuleInfoWithSameProvider == -1) { 
                                    info1._indexOfFirstRuleInfoWithSameProvider = i;
                                } 
 
                                info2._indexOfFirstRuleInfoWithSameProvider = i;
 
                            }
                        }
                    }
                } 

 
#if DBG 
                Debug.Trace("FindRuleInfos", "------------------------------------------------");
                Debug.Trace("FindRuleInfos", "Find ruleInfos for event with type=" + eventType.ToString() + 
                    ", EventCode=" + eventCode);

                foreach(FiringRuleInfo info in matchedRules) {
                    Debug.Trace("FindRuleInfos", "Provider=" + info._ruleInfo._ruleSettings.Provider + 
                        "; eventNameType=" + info._ruleInfo._eventMappingSettings.RealType.ToString() +
                        "; _indexOfFirstRuleInfoWithSameProvider=" + info._indexOfFirstRuleInfoWithSameProvider); 
                } 
                Debug.Trace("FindRuleInfos", "------------------------------------------------");
#endif 

                // save matchedRules in the cache
                if (systemEvent) {
                    _cachedMatchedRules[index0, index1] = matchedRules; 
                }
                else { 
                    Debug.Assert(customWebEventKey != null); 
                    _cachedMatchedRulesForCustomEvents[customWebEventKey] = matchedRules;
                } 

                return matchedRules;
            }
        } 

        internal class RuleInfo { 
            internal string _customEvaluator; 
            internal ConfigurationElement _customEvaluatorConfig;
 
            // The following properties are cached here for performance reason
            internal int _minInstances;
            internal int _maxLimit;
            internal TimeSpan _minInterval;   // in seconds 

            internal RuleSettings _ruleSettings; 
 
            internal WebEventProvider _referencedProvider;
 
            internal Type _customEvaluatorType;

            internal EventMappingSettings _eventMappingSettings;
 
            internal RuleFiringRecord _ruleFiringRecord;
 
            internal RuleInfo(RuleSettings ruleSettings, HealthMonitoringSection section) { 
                _eventMappingSettings = section.EventMappings[ruleSettings.EventName];
 
                _ruleSettings = ruleSettings;
                _ruleFiringRecord = new RuleFiringRecord(this);
            }
 
            internal bool Match(Type eventType, int eventCode) {
                // Fail if the type doesn't match. 
                if (!(eventType.Equals(_eventMappingSettings.RealType) || 
                       eventType.IsSubclassOf(_eventMappingSettings.RealType))) {
                    return false; 
                }

                // Fail if the event code doesn't match
                if (!(_eventMappingSettings.StartEventCode <= eventCode && 
                        eventCode <= _eventMappingSettings.EndEventCode)) {
                    return false; 
                } 

                return true; 
            }
        }

        internal class FiringRuleInfo { 
            internal RuleInfo _ruleInfo;
            internal int _indexOfFirstRuleInfoWithSameProvider; 
 
            internal FiringRuleInfo(RuleInfo ruleInfo) {
                _ruleInfo = ruleInfo; 
                _indexOfFirstRuleInfoWithSameProvider = -1;
            }
        }
 
        internal class ProviderInstances {
            internal Hashtable _instances; // case-insensitive because the providers collection is too. 
 
            internal ProviderInstances(HealthMonitoringSection section) {
                // Build the array of providers 
                // Don't create an instance yet, but only store the providerInfo in the HashTable.
                _instances = CollectionsUtil.CreateCaseInsensitiveHashtable(section.Providers.Count);

                foreach (object obj in section.Providers) { 
                    ProviderSettings settings = (ProviderSettings)obj;
 
                    // Please note we are storing the ProviderSettings in the hashtable. 
                    // But if we create an instance of that provider, we will replace
                    // that string with a provider object. 
                    _instances.Add(settings.Name, settings);
                }
            }
 
            WebEventProvider GetProviderInstance(string providerName) {
                WebEventProvider provider; 
                object o; 

                o = _instances[providerName]; 
                if (o == null) {
                    return null;
                }
 
                ProviderSettings providerSettings = o as ProviderSettings;
 
                if (providerSettings != null) { 
                    // If what we got is still a ProviderSettings, it means we haven't created an instance
                    // of it yet. 
                    Type type;
                    string typeName = providerSettings.Type;

                    type = BuildManager.GetType(typeName, false); 
                    Debug.Assert(type != null, "type != null");
 
                    if (typeof(IInternalWebEventProvider).IsAssignableFrom(type)) { 
                        provider = (WebEventProvider)HttpRuntime.CreateNonPublicInstance(type);
                    } 
                    else {
                        provider = (WebEventProvider)HttpRuntime.CreatePublicInstance(type);
                    }
 
                    using (new ProcessImpersonationContext()) {
                        try { 
                            provider.Initialize(providerSettings.Name, providerSettings.Parameters); 
                        }
                        catch (ConfigurationErrorsException) { 
                            throw;
                        }
                        catch (ConfigurationException e) {
                            throw new ConfigurationErrorsException(e.Message, providerSettings.ElementInformation.Properties["type"].Source, 
                                providerSettings.ElementInformation.Properties["type"].LineNumber);
                        } 
                        catch { 
                            throw;
                        } 
                    }

                    Debug.Trace("ProviderInstances", "Create a provider instance: " +
                        "name=" + providerSettings.Name + ";type=" + typeName); 

                    _instances[providerName] = provider; 
                } 
                else {
                    provider = o as WebEventProvider; 
                    Debug.Assert(provider != null, "provider != null");
                }

                return provider; 
            }
 
            internal WebEventProvider this[String name] { 
                get {
                    return GetProviderInstance(name); 
                }
            }

            // Cleanup each provider for which we have NOT created an instance. 
            internal void CleanupUninitProviders() {
                ArrayList list = new ArrayList(); 
 
                foreach (DictionaryEntry de in _instances) {
                    if (de.Value is ProviderSettings) { 
                        list.Add(de.Key);
                    }
                }
 
                foreach (object o in list) {
                    Debug.Trace("ProviderInstances", "Remove " + (string)o + " from providers"); 
                    _instances.Remove(o); 
                }
            } 

            internal bool ContainsKey(string name) {
                return _instances.ContainsKey(name);
            } 

            public IDictionaryEnumerator GetEnumerator() { 
                return _instances.GetEnumerator(); 
            }
        } 
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK