HttpApplicationFactory.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ FXUpdate3074 / FXUpdate3074 / 1.1 / untmp / whidbey / QFE / ndp / fx / src / xsp / System / Web / HttpApplicationFactory.cs / 4 / HttpApplicationFactory.cs

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

/* 
 * The HttpApplicationFactory class 
 *
 * Copyright (c) 1999 Microsoft Corporation 
 */

namespace System.Web {
    using System.Text; 
    using System.Threading;
    using System.Runtime.Remoting.Messaging; 
    using System.Web; 
    using System.Web.Caching;
    using System.Web.Util; 
    using System.Web.Hosting;
    using System.Web.UI;
    using System.Web.Compilation;
    using System.Web.SessionState; 
    using System.Collections;
    using System.Reflection; 
    using System.IO; 
    using System.Globalization;
    using System.Web.Management; 

    /*
     * Application Factory only has and public static methods to get / recycle
     * application instances.  The information cached per application 
     * config file is encapsulated by ApplicationData class.
     * Only one static instance of application factory is created. 
     */ 
    internal class HttpApplicationFactory {
 
        internal const string applicationFileName = "global.asax";

        // the only instance of application factory
        private static HttpApplicationFactory _theApplicationFactory = new HttpApplicationFactory(); 

        // flag to indicate that initialization was done 
        private bool _inited; 

        // filename for the global.asax 
        private String _appFilename;
        private ICollection _fileDependencies;

        // call application on_start only once 
        private bool _appOnStartCalled = false;
 
        // call application on_end only once 
        private bool _appOnEndCalled = false;
 
        // dictionary of application state
        private HttpApplicationState _state;

        // class of the application object 
        private Type _theApplicationType;
 
        // free list of app objects 
        private Stack _freeList = new Stack();
        private int _numFreeAppInstances = 0; 
        private const int _maxFreeAppInstances = 100;
        private int _minFreeAppInstances = 0;

        // free list of special (context-less) app objects 
        // to be used for global events (App_OnEnd, Session_OnEnd, etc.)
        private Stack _specialFreeList = new Stack(); 
        private int _numFreeSpecialAppInstances = 0; 
        private const int _maxFreeSpecialAppInstances = 20;
 
        // results of the reflection on the app class
        private MethodInfo   _onStartMethod;        // Application_OnStart
        private int          _onStartParamCount;
        private MethodInfo   _onEndMethod;          // Application_OnEnd 
        private int          _onEndParamCount;
        private MethodInfo   _sessionOnEndMethod;   // Session_OnEnd 
        private int          _sessionOnEndParamCount; 
        private EventHandler _sessionOnEndEventHandlerAspCompatHelper; // helper for AspCompat
        // list of methods suspected as event handlers 
        private MethodInfo[] _eventHandlerMethods;


        internal HttpApplicationFactory() { 
            _sessionOnEndEventHandlerAspCompatHelper = new EventHandler(this.SessionOnEndEventHandlerAspCompatHelper);
        } 
 
        //
        // Initialization on first request 
        //

        private void Init() {
            if (_customApplication != null) 
                return;
 
            try { 
                try {
                    _appFilename = GetApplicationFile(); 

                    CompileApplication();
                }
                finally { 
                    // Always set up global.asax file change notification, even if compilation
                    // failed.  This way, if the problem is fixed, the appdomain will be restarted. 
                    SetupChangesMonitor(); 
                }
            } 
            catch { // Protect against exception filters
                throw;
            }
        } 

        internal static void SetupFileChangeNotifications() { 
            // Just call EnsureInited() to make sure global.asax FCN are set up. 
            // But don't if we never even got to initialize Fusion
            if (HttpRuntime.CodegenDirInternal != null) 
                _theApplicationFactory.EnsureInited();
        }

        private void EnsureInited() { 
            if (!_inited) {
                lock (this) { 
                    if (!_inited) { 
                        Init();
                        _inited = true; 
                    }
                }
            }
        } 

        internal static void EnsureAppStartCalledForIntegratedMode(HttpContext context, HttpApplication app) { 
            if (!_theApplicationFactory._appOnStartCalled) { 
                Exception error = null;
                lock (_theApplicationFactory) { 
                    if (!_theApplicationFactory._appOnStartCalled) {
                        using (new HttpContextWrapper(context)) {
                            // impersonation could be required (UNC share or app credentials)
 
                            WebBaseEvent.RaiseSystemEvent(_theApplicationFactory, WebEventCodes.ApplicationStart);
 
                            if (_theApplicationFactory._onStartMethod != null) { 
                                app.ProcessSpecialRequest(context,
                                                          _theApplicationFactory._onStartMethod, 
                                                          _theApplicationFactory._onStartParamCount,
                                                          _theApplicationFactory,
                                                          EventArgs.Empty,
                                                          null); 
                            }
                        } 
                    } 

                    _theApplicationFactory._appOnStartCalled = true; 
                    error = context.Error;
                }
                if (error != null) {
                    throw new HttpException(error.Message, error); 
                }
            } 
        } 

        private void EnsureAppStartCalled(HttpContext context) { 
            if (!_appOnStartCalled) {
                lock (this) {
                    if (!_appOnStartCalled) {
                        using (new HttpContextWrapper(context)) { 
                            // impersonation could be required (UNC share or app credentials)
 
                            WebBaseEvent.RaiseSystemEvent(this, WebEventCodes.ApplicationStart); 

                            // fire outside of impersonation as HttpApplication logic takes 
                            // care of impersonation by itself
                            FireApplicationOnStart(context);
                        }
 
                        _appOnStartCalled = true;
                    } 
                } 
            }
        } 

        internal static String GetApplicationFile() {
            return Path.Combine(HttpRuntime.AppDomainAppPathInternal, applicationFileName);
        } 

        private void CompileApplication() { 
            // Get the Application Type and AppState from the global file 

            _theApplicationType = BuildManager.GetGlobalAsaxType(); 

            BuildResultCompiledGlobalAsaxType result = BuildManager.GetGlobalAsaxBuildResult();

            if (result != null) { 

                // Even if global.asax was already compiled, we need to get the collections 
                // of application and session objects, since they are not persisted when 
                // global.asax is compiled.  Ideally, they would be, but since  tags
                // are only there for ASP compat, it's not worth the trouble. 
                // Note that we only do this is the rare case where we know global.asax contains
                //  tags, to avoid always paying the price (
                if (result.HasAppOrSessionObjects) {
                    GetAppStateByParsingGlobalAsax(); 
                }
 
                // Remember file dependencies 
                _fileDependencies = result.VirtualPathDependencies;
            } 

            if (_state == null) {
                _state = new HttpApplicationState();
            } 

 
            // Prepare to hookup event handlers via reflection 

            ReflectOnApplicationType(); 
        }

        private void GetAppStateByParsingGlobalAsax() {
            using (new ApplicationImpersonationContext()) { 
                // It may not exist if the app is precompiled
                if (FileUtil.FileExists(_appFilename)) { 
                    ApplicationFileParser parser; 

                    parser = new ApplicationFileParser(); 
                    AssemblySet referencedAssemblies = System.Web.UI.Util.GetReferencedAssemblies(
                        _theApplicationType.Assembly);
                    referencedAssemblies.Add(typeof(string).Assembly);
                    VirtualPath virtualPath = HttpRuntime.AppDomainAppVirtualPathObject.SimpleCombine( 
                        applicationFileName);
                    parser.Parse(referencedAssemblies, virtualPath); 
 
                    // Create app state
                    _state = new HttpApplicationState(parser.ApplicationObjects, parser.SessionObjects); 
                }
            }
        }
 
        private bool ReflectOnMethodInfoIfItLooksLikeEventHandler(MethodInfo m) {
            if (m.ReturnType != typeof(void)) 
                return false; 

            // has to have either no args or two args (object, eventargs) 
            ParameterInfo[] parameters = m.GetParameters();

            switch (parameters.Length) {
                case 0: 
                    // ok
                    break; 
                case 2: 
                    // param 0 must be object
                    if (parameters[0].ParameterType != typeof(System.Object)) 
                        return false;
                    // param 1 must be eventargs
                    if (parameters[1].ParameterType != typeof(System.EventArgs) &&
                        !parameters[1].ParameterType.IsSubclassOf(typeof(System.EventArgs))) 
                        return false;
                    // ok 
                    break; 

                default: 
                    return false;
            }

            // 
            String name = m.Name;
            int j = name.IndexOf('_'); 
            if (j <= 0 || j > name.Length-1) 
                return false;
 
            // special pseudo-events
            if (StringUtil.EqualsIgnoreCase(name, "Application_OnStart") ||
                StringUtil.EqualsIgnoreCase(name, "Application_Start")) {
                _onStartMethod = m; 
                _onStartParamCount = parameters.Length;
            } 
            else if (StringUtil.EqualsIgnoreCase(name, "Application_OnEnd") || 
                     StringUtil.EqualsIgnoreCase(name, "Application_End")) {
                _onEndMethod = m; 
                _onEndParamCount = parameters.Length;
            }
            else if (StringUtil.EqualsIgnoreCase(name, "Session_OnEnd") ||
                     StringUtil.EqualsIgnoreCase(name, "Session_End")) { 
                _sessionOnEndMethod = m;
                _sessionOnEndParamCount = parameters.Length; 
            } 

            return true; 
        }

        private void ReflectOnApplicationType() {
            ArrayList handlers = new ArrayList(); 
            MethodInfo[] methods;
 
            Debug.Trace("PipelineRuntime", "ReflectOnApplicationType"); 

            // get this class methods 
            methods = _theApplicationType.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);
            foreach (MethodInfo m in methods) {
                if (ReflectOnMethodInfoIfItLooksLikeEventHandler(m))
                    handlers.Add(m); 
            }
 
            // get base class private methods (GetMethods would not return those) 
            Type baseType = _theApplicationType.BaseType;
            if (baseType != null && baseType != typeof(HttpApplication)) { 
                methods = baseType.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
                foreach (MethodInfo m in methods) {
                    if (m.IsPrivate && ReflectOnMethodInfoIfItLooksLikeEventHandler(m))
                        handlers.Add(m); 
                }
            } 
 
            // remember as an array
            _eventHandlerMethods = new MethodInfo[handlers.Count]; 
            for (int i = 0; i < _eventHandlerMethods.Length; i++)
                _eventHandlerMethods[i] = (MethodInfo)handlers[i];
        }
 
        private void SetupChangesMonitor() {
            FileChangeEventHandler handler = new FileChangeEventHandler(this.OnAppFileChange); 
 
            HttpRuntime.FileChangesMonitor.StartMonitoringFile(_appFilename, handler);
 
            if (_fileDependencies != null) {
                foreach (string fileName in _fileDependencies) {
                    HttpRuntime.FileChangesMonitor.StartMonitoringFile(
                        HostingEnvironment.MapPathInternal(fileName), handler); 
                }
            } 
        } 

        private void OnAppFileChange(Object sender, FileChangeEvent e) { 
            // shutdown the app domain if app file changed
            Debug.Trace("AppDomainFactory", "Shutting down appdomain because of application file change");
            HttpRuntime.ShutdownAppDomain(ApplicationShutdownReason.ChangeInGlobalAsax, "Change in GLOBAL.ASAX");
        } 

        // 
        //  Application instance management 
        //
 
        private HttpApplication GetNormalApplicationInstance(HttpContext context) {
            HttpApplication app = null;

            lock (_freeList) { 
                if (_numFreeAppInstances > 0) {
                    app = (HttpApplication)_freeList.Pop(); 
                    _numFreeAppInstances--; 

                    if (_numFreeAppInstances < _minFreeAppInstances) { 
                        _minFreeAppInstances = _numFreeAppInstances;
                    }
                }
            } 

            if (app == null) { 
                // If ran out of instances, create a new one 
                app = (HttpApplication)HttpRuntime.CreateNonPublicInstance(_theApplicationType);
 
                using (new ApplicationImpersonationContext()) {
                    app.InitInternal(context, _state, _eventHandlerMethods);
                }
            } 

            return app; 
        } 

        private void RecycleNormalApplicationInstance(HttpApplication app) { 
            if (_numFreeAppInstances < _maxFreeAppInstances) {
                lock (_freeList) {
                    _freeList.Push(app);
                    _numFreeAppInstances++; 
                }
            } 
            else { 
                app.DisposeInternal();
            } 
        }

        private void TrimApplicationInstanceFreeList() {
            // reset last min length 
            int minFreeAppInstances = _minFreeAppInstances;
            _minFreeAppInstances = _numFreeAppInstances; 
 
            // if free list is empty or was empty since last trim, don't trim now
            if (minFreeAppInstances <= 1) { 
                return;
            }

            HttpApplication app = null; 

            lock (_freeList) { 
                if (_numFreeAppInstances > 1) { 
                    app = (HttpApplication)_freeList.Pop();
                    _numFreeAppInstances--; 

                    _minFreeAppInstances = _numFreeAppInstances;
                }
            } 

            // dispose the application that was removed (if any) 
            if (app != null) { 
                app.DisposeInternal();
            } 
        }

        internal static HttpApplication GetPipelineApplicationInstance(IntPtr appContext, HttpContext context) {
            _theApplicationFactory.EnsureInited(); 
            return _theApplicationFactory.GetSpecialApplicationInstance(appContext, context);
        } 
 
        internal static void RecyclePipelineApplicationInstance(HttpApplication app) {
            _theApplicationFactory.RecycleSpecialApplicationInstance(app); 
        }

        private HttpApplication GetSpecialApplicationInstance(IntPtr appContext, HttpContext context) {
            HttpApplication app = null; 

            lock (_specialFreeList) { 
                if (_numFreeSpecialAppInstances > 0) { 
                    app = (HttpApplication)_specialFreeList.Pop();
                    _numFreeSpecialAppInstances--; 
                }
            }

            if (app == null) { 
                //
                //  Put the context on the thread, to make it available to anyone calling 
                //  HttpContext.Current from the HttpApplication constructor or module Init 
                //
                using (new HttpContextWrapper(context)) { 
                    // If ran out of instances, create a new one
                    app = (HttpApplication)HttpRuntime.CreateNonPublicInstance(_theApplicationType);

                    using (new ApplicationImpersonationContext()) { 
                        app.InitSpecial(_state, _eventHandlerMethods, appContext, context);
                    } 
                } 
            }
 
            return app;
        }

        private HttpApplication GetSpecialApplicationInstance() { 
            return GetSpecialApplicationInstance(IntPtr.Zero, null);
        } 
 
        private void RecycleSpecialApplicationInstance(HttpApplication app) {
            if (_numFreeSpecialAppInstances < _maxFreeSpecialAppInstances) { 
                lock (_specialFreeList) {
                    _specialFreeList.Push(app);
                    _numFreeSpecialAppInstances++;
                } 
            }
            // else: don't dispose these 
        } 

        // 
        //  Application on_start / on_end
        //

        private void FireApplicationOnStart(HttpContext context) { 
            if (_onStartMethod != null) {
                HttpApplication app = GetSpecialApplicationInstance(); 
 
                app.ProcessSpecialRequest(
                                         context, 
                                         _onStartMethod,
                                         _onStartParamCount,
                                         this,
                                         EventArgs.Empty, 
                                         null);
 
                RecycleSpecialApplicationInstance(app); 
            }
        } 

        private void FireApplicationOnEnd() {
            if (_onEndMethod != null) {
                HttpApplication app = GetSpecialApplicationInstance(); 

                app.ProcessSpecialRequest( 
                                         null, 
                                         _onEndMethod,
                                         _onEndParamCount, 
                                         this,
                                         EventArgs.Empty,
                                         null);
 
                RecycleSpecialApplicationInstance(app);
            } 
        } 

        // 
        //  Session on_start / on_end
        //

        class AspCompatSessionOnEndHelper { 
            private HttpApplication _app;
            private HttpSessionState _session; 
            private Object _eventSource; 
            private EventArgs _eventArgs;
 
            internal AspCompatSessionOnEndHelper(HttpApplication app, HttpSessionState session, Object eventSource, EventArgs eventArgs) {
                _app = app;
                _session = session;
                _eventSource = eventSource; 
                _eventArgs = eventArgs;
            } 
 
            internal HttpApplication Application { get { return _app; } }
            internal HttpSessionState Session { get { return _session; } } 
            internal Object Source { get { return _eventSource; } }
            internal EventArgs Args { get { return _eventArgs; } }
        }
 
        private void SessionOnEndEventHandlerAspCompatHelper(Object eventSource, EventArgs eventArgs) {
            AspCompatSessionOnEndHelper helper = (AspCompatSessionOnEndHelper)eventSource; 
 
            helper.Application.ProcessSpecialRequest(
                                                     null, 
                                                     _sessionOnEndMethod,
                                                     _sessionOnEndParamCount,
                                                     helper.Source,
                                                     helper.Args, 
                                                     helper.Session);
        } 
 
        private void FireSessionOnEnd(HttpSessionState session, Object eventSource, EventArgs eventArgs) {
            if (_sessionOnEndMethod != null) { 
                HttpApplication app = GetSpecialApplicationInstance();
#if !FEATURE_PAL // FEATURE_PAL does not enable COM
                if (AspCompatApplicationStep.AnyStaObjectsInSessionState(session) || HttpRuntime.ApartmentThreading) {
                    AspCompatSessionOnEndHelper helper = new AspCompatSessionOnEndHelper(app, session, eventSource, eventArgs); 

                    AspCompatApplicationStep.RaiseAspCompatEvent( 
                                            null, 
                                            app,
                                            session.SessionID, 
                                            _sessionOnEndEventHandlerAspCompatHelper,
                                            helper,
                                            EventArgs.Empty);
                } 
                else {
#endif // !FEATURE_PAL 
                    app.ProcessSpecialRequest( 
                                            null,
                                            _sessionOnEndMethod, 
                                            _sessionOnEndParamCount,
                                            eventSource,
                                            eventArgs,
                                            session); 
#if !FEATURE_PAL // FEATURE_PAL does not enable COM
                } 
#endif // !FEATURE_PAL 

                RecycleSpecialApplicationInstance(app); 
            }
        }

        private void FireApplicationOnError(Exception error) { 
            HttpApplication app = GetSpecialApplicationInstance();
            app.RaiseErrorWithoutContext(error); 
            RecycleSpecialApplicationInstance(app); 
        }
 
        //
        //  Dispose resources associated with the app factory
        //
 
        private void Dispose() {
            // dispose all app instances 
 
            ArrayList apps = new ArrayList();
 
            lock (_freeList) {
                while (_numFreeAppInstances > 0) {
                    apps.Add(_freeList.Pop());
                    _numFreeAppInstances--; 
                }
            } 
 
            int n = apps.Count;
 
            for (int i = 0; i < n; i++)
                ((HttpApplication)(apps[i])).DisposeInternal();

            // call application_onEnd (only if application_onStart was called before) 

            if (_appOnStartCalled && !_appOnEndCalled) { 
                lock (this) { 
                    if (!_appOnEndCalled) {
                        FireApplicationOnEnd(); 
                        _appOnEndCalled = true;
                    }
                }
            } 
        }
 
        // 
        // Static methods for outside use
        // 

        // custom application -- every request goes directly to the same handler
        private static IHttpHandler _customApplication;
 
        internal static void SetCustomApplication(IHttpHandler customApplication) {
            // ignore this in app domains where we execute requests (ASURT 128047) 
            if (HttpRuntime.AppDomainAppIdInternal == null) // only if 'clean' app domain 
                _customApplication = customApplication;
        } 

        internal static IHttpHandler GetApplicationInstance(HttpContext context) {
            if (_customApplication != null)
                return _customApplication; 

            // Check to see if it's a debug auto-attach request 
            if (context.Request.IsDebuggingRequest) 
                return new HttpDebugHandler();
 
            _theApplicationFactory.EnsureInited();

            _theApplicationFactory.EnsureAppStartCalled(context);
 
            return _theApplicationFactory.GetNormalApplicationInstance(context);
        } 
 
        internal static void RecycleApplicationInstance(HttpApplication app) {
            _theApplicationFactory.RecycleNormalApplicationInstance(app); 
        }

        internal static void TrimApplicationInstances() {
            if (_theApplicationFactory != null) { 
                _theApplicationFactory.TrimApplicationInstanceFreeList();
            } 
        } 

        internal static void EndApplication() { 
            _theApplicationFactory.Dispose();
        }

        internal static void EndSession(HttpSessionState session, Object eventSource, EventArgs eventArgs) { 
            _theApplicationFactory.FireSessionOnEnd(session, eventSource, eventArgs);
        } 
 
        internal static void RaiseError(Exception error) {
            _theApplicationFactory.EnsureInited(); // 
            _theApplicationFactory.FireApplicationOnError(error);
        }

        internal static HttpApplicationState ApplicationState { 
            get {
                HttpApplicationState state = _theApplicationFactory._state; 
                if (state == null) 
                    state = new HttpApplicationState();
                return state; 
            }
        }
    }
 
}

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


                        

                        

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