Code:
/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / whidbey / NetFXspW7 / ndp / fx / src / xsp / System / Web / HttpApplicationFactory.cs / 1 / 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 (VSWhidbey 453101)
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;
}
// check the name (has to have _ not as first or last char)
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(); // VSWhidbey 482346
_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.
//
//-----------------------------------------------------------------------------
/*
* 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 (VSWhidbey 453101)
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;
}
// check the name (has to have _ not as first or last char)
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(); // VSWhidbey 482346
_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.