2 // System.Web.HttpApplicationFactory
\r
5 // Patrik Torstensson (ptorsten@hotmail.com)
\r
6 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
\r
8 // (c) 2002,2003 Ximian, Inc. (http://www.ximian.com)
\r
11 using System.Collections;
\r
13 using System.Reflection;
\r
14 using System.Web.UI;
\r
15 using System.Web.Compilation;
\r
16 using System.Web.SessionState;
\r
18 namespace System.Web {
\r
19 class HttpApplicationFactory {
\r
20 private string _appFilename;
\r
21 private Type _appType;
\r
23 private bool _appInitialized;
\r
24 private bool _appFiredEnd;
\r
26 private Stack _appFreePublicList;
\r
27 private int _appFreePublicInstances;
\r
28 static private int _appMaxFreePublicInstances = 32;
\r
30 private HttpApplicationState _state;
\r
32 static IHttpHandler custApplication;
\r
34 static private HttpApplicationFactory s_Factory = new HttpApplicationFactory();
\r
36 public HttpApplicationFactory() {
\r
37 _appInitialized = false;
\r
38 _appFiredEnd = false;
\r
40 _appFreePublicList = new Stack();
\r
41 _appFreePublicInstances = 0;
\r
44 static private string GetAppFilename (HttpContext context)
\r
46 string physicalAppPath = context.Request.PhysicalApplicationPath;
\r
47 string appFilePath = Path.Combine (physicalAppPath, "Global.asax");
\r
48 if (File.Exists (appFilePath))
\r
51 return Path.Combine (physicalAppPath, "global.asax");
\r
54 private void CompileApp(HttpContext context) {
\r
55 if (File.Exists(_appFilename)) {
\r
56 // Setup filemonitor for all filedepend also. CacheDependency?
\r
58 _appType = ApplicationFileParser.GetCompiledApplicationType (_appFilename, context);
\r
59 if (_appType == null) {
\r
60 string msg = String.Format ("Error compiling application file ({0}).", _appFilename);
\r
61 throw new ApplicationException (msg);
\r
64 _appType = typeof (System.Web.HttpApplication);
\r
65 _state = new HttpApplicationState ();
\r
69 static bool IsEventHandler (MethodInfo m)
\r
71 if (m.ReturnType != typeof (void))
\r
74 ParameterInfo [] pi = m.GetParameters ();
\r
75 int length = pi.Length;
\r
82 if (pi [0].ParameterType != typeof (object) ||
\r
83 pi [1].ParameterType != typeof (EventArgs))
\r
89 static void AddEvent (MethodInfo method, Hashtable appTypeEventHandlers)
\r
91 string name = method.Name.Replace ("_On", "_");
\r
92 if (appTypeEventHandlers [name] == null) {
\r
93 appTypeEventHandlers [name] = method;
\r
98 if (appTypeEventHandlers [name] is MethodInfo)
\r
99 list = new ArrayList ();
\r
101 list = appTypeEventHandlers [name] as ArrayList;
\r
106 static Hashtable GetApplicationTypeEvents (HttpApplication app)
\r
108 Type appType = app.GetType ();
\r
109 Hashtable appTypeEventHandlers = new Hashtable ();
\r
110 ArrayList evtMethods = new ArrayList ();
\r
111 BindingFlags flags = BindingFlags.Public |
\r
112 BindingFlags.NonPublic |
\r
113 BindingFlags.Instance |
\r
114 BindingFlags.Static;
\r
116 MethodInfo [] methods = appType.GetMethods (flags);
\r
117 foreach (MethodInfo m in methods) {
\r
118 if (IsEventHandler (m))
\r
119 AddEvent (m, appTypeEventHandlers);
\r
122 return appTypeEventHandlers;
\r
125 static bool FireEvents (string method_name, object target, object [] args)
\r
127 Hashtable possibleEvents = GetApplicationTypeEvents ((HttpApplication) target);
\r
128 MethodInfo method = possibleEvents [method_name] as MethodInfo;
\r
129 if (method == null)
\r
132 if (method.GetParameters ().Length == 0)
\r
133 method.Invoke (target, null);
\r
135 method.Invoke (target, args);
\r
140 internal static void FireOnAppStart (HttpApplication app)
\r
142 object [] args = new object [] {app, EventArgs.Empty};
\r
143 FireEvents ("Application_Start", app, args);
\r
146 void FireOnAppEnd ()
\r
148 // FireEvents ("Application_End", this, new object [] {this, EventArgs.Empty});
\r
151 void FireOnSessionStart (HttpSessionState state, object source, EventArgs args)
\r
153 // FireEvents ("Session_Start", state, new object [] {source, EventArgs.Empty});
\r
156 void FireOnSessionEnd (HttpSessionState state, object source, EventArgs args)
\r
158 // FireEvents ("Session_End", state, new object [] {source, args});
\r
161 private void InitializeFactory (HttpContext context)
\r
163 _appFilename = GetAppFilename (context);
\r
165 CompileApp (context);
\r
167 // Create a application object
\r
168 HttpApplication app = (HttpApplication) HttpRuntime.CreateInternalObject (_appType);
\r
171 app.Startup(context, HttpApplicationFactory.ApplicationState);
\r
174 HttpApplicationFactory.FireOnAppStart (app);
\r
176 // Recycle our application instance
\r
177 RecyclePublicInstance(app);
\r
180 private void Dispose() {
\r
181 ArrayList torelease = new ArrayList();
\r
182 lock (_appFreePublicList) {
\r
183 while (_appFreePublicList.Count > 0) {
\r
184 torelease.Add(_appFreePublicList.Pop());
\r
185 _appFreePublicInstances--;
\r
189 if (torelease.Count > 0) {
\r
190 foreach (Object obj in torelease) {
\r
191 ((HttpApplication) obj).Cleanup();
\r
195 if (!_appFiredEnd) {
\r
197 if (!_appFiredEnd) {
\r
199 _appFiredEnd = true;
\r
205 internal static IHttpHandler GetInstance(HttpContext context)
\r
207 if (custApplication != null)
\r
208 return custApplication;
\r
210 if (!s_Factory._appInitialized) {
\r
212 if (!s_Factory._appInitialized) {
\r
213 s_Factory.InitializeFactory(context);
\r
214 s_Factory._appInitialized = true;
\r
219 return s_Factory.GetPublicInstance(context);
\r
222 internal static void RecycleInstance(HttpApplication app) {
\r
223 if (!s_Factory._appInitialized)
\r
224 throw new InvalidOperationException("Factory not intialized");
\r
226 s_Factory.RecyclePublicInstance(app);
\r
229 internal static void AttachEvents (HttpApplication app)
\r
231 Hashtable possibleEvents = GetApplicationTypeEvents (app);
\r
232 foreach (string key in possibleEvents.Keys) {
\r
233 int pos = key.IndexOf ('_');
\r
234 if (pos == -1 || key.Length <= pos + 1)
\r
237 string moduleName = key.Substring (0, pos);
\r
239 if (moduleName == "Application") {
\r
242 target = app.Modules [moduleName];
\r
245 string eventName = key.Substring (pos + 1);
\r
246 EventInfo evt = target.GetType ().GetEvent (eventName);
\r
250 string usualName = moduleName + "_" + eventName;
\r
251 object methodData = possibleEvents [usualName];
\r
252 if (methodData == null)
\r
255 if (methodData is MethodInfo) {
\r
256 AddHandler (evt, target, app, (MethodInfo) methodData);
\r
260 ArrayList list = (ArrayList) methodData;
\r
261 foreach (MethodInfo method in list)
\r
262 AddHandler (evt, target, app, method);
\r
266 static void AddHandler (EventInfo evt, object target, HttpApplication app, MethodInfo method)
\r
268 int length = method.GetParameters ().Length;
\r
271 NoParamsInvoker npi = new NoParamsInvoker (app, method.Name);
\r
272 evt.AddEventHandler (target, npi.FakeDelegate);
\r
274 evt.AddEventHandler (target, Delegate.CreateDelegate (
\r
275 typeof (EventHandler), app, method.Name));
\r
279 private IHttpHandler GetPublicInstance(HttpContext context) {
\r
280 HttpApplication app = null;
\r
282 lock (_appFreePublicList) {
\r
283 if (_appFreePublicInstances > 0) {
\r
284 app = (HttpApplication) _appFreePublicList.Pop();
\r
285 _appFreePublicInstances--;
\r
290 // Create non-public object
\r
291 app = (HttpApplication) HttpRuntime.CreateInternalObject(_appType);
\r
293 app.Startup(context, HttpApplicationFactory.ApplicationState);
\r
296 return (IHttpHandler) app;
\r
299 internal void RecyclePublicInstance(HttpApplication app) {
\r
300 lock (_appFreePublicList) {
\r
301 if (_appFreePublicInstances < _appMaxFreePublicInstances) {
\r
302 _appFreePublicList.Push(app);
\r
303 _appFreePublicInstances++;
\r
314 static HttpStaticObjectsCollection MakeStaticCollection (ArrayList list)
\r
316 if (list == null || list.Count == 0)
\r
319 HttpStaticObjectsCollection coll = new HttpStaticObjectsCollection ();
\r
320 foreach (ObjectTagBuilder tag in list) {
\r
327 static internal HttpApplicationState ApplicationState {
\r
329 if (null == s_Factory._state) {
\r
330 HttpStaticObjectsCollection app = MakeStaticCollection (GlobalAsaxCompiler.ApplicationObjects);
\r
331 HttpStaticObjectsCollection ses = MakeStaticCollection (GlobalAsaxCompiler.SessionObjects);
\r
332 s_Factory._state = new HttpApplicationState (app, ses);
\r
335 return s_Factory._state;
\r
339 internal static void EndApplication() {
\r
340 s_Factory.Dispose();
\r
343 public static void SetCustomApplication (IHttpHandler customApplication)
\r
345 custApplication = customApplication;
\r
348 internal Type AppType {
\r
349 get { return _appType; }
\r