2 // System.Web.HttpApplicationFactory
5 // Patrik Torstensson (ptorsten@hotmail.com)
6 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
8 // (c) 2002,2003 Ximian, Inc. (http://www.ximian.com)
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 using System
.Collections
;
34 using System
.Reflection
;
36 using System
.Web
.Compilation
;
37 using System
.Web
.SessionState
;
39 namespace System
.Web
{
40 class HttpApplicationFactory
{
41 private string _appFilename
;
42 private Type _appType
;
44 private bool _appInitialized
;
45 private bool _appFiredEnd
;
47 private Stack _appFreePublicList
;
48 private int _appFreePublicInstances
;
49 static private int _appMaxFreePublicInstances
= 32;
51 private HttpApplicationState _state
;
53 static IHttpHandler custApplication
;
55 static private HttpApplicationFactory s_Factory
= new HttpApplicationFactory();
57 public HttpApplicationFactory() {
58 _appInitialized
= false;
61 _appFreePublicList
= new Stack();
62 _appFreePublicInstances
= 0;
65 static private string GetAppFilename (HttpContext context
)
67 string physicalAppPath
= context
.Request
.PhysicalApplicationPath
;
68 string appFilePath
= Path
.Combine (physicalAppPath
, "Global.asax");
69 if (File
.Exists (appFilePath
))
72 return Path
.Combine (physicalAppPath
, "global.asax");
75 private void CompileApp(HttpContext context
) {
76 if (File
.Exists(_appFilename
)) {
77 // Setup filemonitor for all filedepend also. CacheDependency?
79 _appType
= ApplicationFileParser
.GetCompiledApplicationType (_appFilename
, context
);
80 if (_appType
== null) {
81 string msg
= String
.Format ("Error compiling application file ({0}).", _appFilename
);
82 throw new ApplicationException (msg
);
85 _appType
= typeof (System
.Web
.HttpApplication
);
86 _state
= new HttpApplicationState ();
90 static bool IsEventHandler (MethodInfo m
)
92 if (m
.ReturnType
!= typeof (void))
95 ParameterInfo
[] pi
= m
.GetParameters ();
96 int length
= pi
.Length
;
103 if (pi
[0].ParameterType
!= typeof (object) ||
104 pi
[1].ParameterType
!= typeof (EventArgs
))
110 static void AddEvent (MethodInfo method
, Hashtable appTypeEventHandlers
)
112 string name
= method
.Name
.Replace ("_On", "_");
113 if (appTypeEventHandlers
[name
] == null) {
114 appTypeEventHandlers
[name
] = method
;
119 if (appTypeEventHandlers
[name
] is MethodInfo
)
120 list
= new ArrayList ();
122 list
= appTypeEventHandlers
[name
] as ArrayList
;
127 static Hashtable
GetApplicationTypeEvents (HttpApplication app
)
129 Type appType
= app
.GetType ();
130 Hashtable appTypeEventHandlers
= new Hashtable ();
131 ArrayList evtMethods
= new ArrayList ();
132 BindingFlags flags
= BindingFlags
.Public
|
133 BindingFlags
.NonPublic
|
134 BindingFlags
.Instance
|
137 MethodInfo
[] methods
= appType
.GetMethods (flags
);
138 foreach (MethodInfo m
in methods
) {
139 if (IsEventHandler (m
))
140 AddEvent (m
, appTypeEventHandlers
);
143 return appTypeEventHandlers
;
146 static bool FireEvent (string method_name
, object target
, object [] args
)
148 Hashtable possibleEvents
= GetApplicationTypeEvents ((HttpApplication
) target
);
149 MethodInfo method
= possibleEvents
[method_name
] as MethodInfo
;
153 if (method
.GetParameters ().Length
== 0)
154 method
.Invoke (target
, null);
156 method
.Invoke (target
, args
);
161 internal static void FireOnAppStart (HttpApplication app
)
163 object [] args
= new object [] {app, EventArgs.Empty}
;
164 FireEvent ("Application_Start", app
, args
);
169 if (_appType
== null)
170 return; // we didn't even get an application
172 HttpApplication app
= (HttpApplication
) HttpRuntime
.CreateInternalObject (_appType
);
174 FireEvent ("Application_End", app
, new object [] {this, EventArgs.Empty}
);
178 private void InitializeFactory (HttpContext context
)
180 _appFilename
= GetAppFilename (context
);
182 CompileApp (context
);
184 // Create a application object
185 HttpApplication app
= (HttpApplication
) HttpRuntime
.CreateInternalObject (_appType
);
188 app
.Startup(context
, HttpApplicationFactory
.ApplicationState
);
191 HttpApplicationFactory
.FireOnAppStart (app
);
193 // Recycle our application instance
194 RecyclePublicInstance(app
);
197 private void Dispose() {
198 ArrayList torelease
= new ArrayList();
199 lock (_appFreePublicList
) {
200 while (_appFreePublicList
.Count
> 0) {
201 torelease
.Add(_appFreePublicList
.Pop());
202 _appFreePublicInstances
--;
206 if (torelease
.Count
> 0) {
207 foreach (Object obj
in torelease
) {
208 ((HttpApplication
) obj
).Cleanup();
222 internal static IHttpHandler
GetInstance(HttpContext context
)
224 if (custApplication
!= null)
225 return custApplication
;
227 if (!s_Factory
._appInitialized
) {
229 if (!s_Factory
._appInitialized
) {
230 s_Factory
.InitializeFactory(context
);
231 s_Factory
._appInitialized
= true;
236 return s_Factory
.GetPublicInstance(context
);
239 internal static void RecycleInstance(HttpApplication app
) {
240 if (!s_Factory
._appInitialized
)
241 throw new InvalidOperationException("Factory not intialized");
243 s_Factory
.RecyclePublicInstance(app
);
246 internal static void AttachEvents (HttpApplication app
)
248 Hashtable possibleEvents
= GetApplicationTypeEvents (app
);
249 foreach (string key
in possibleEvents
.Keys
) {
250 int pos
= key
.IndexOf ('_');
251 if (pos
== -1 || key
.Length
<= pos
+ 1)
254 string moduleName
= key
.Substring (0, pos
);
256 if (moduleName
== "Application") {
259 target
= app
.Modules
[moduleName
];
264 string eventName
= key
.Substring (pos
+ 1);
265 EventInfo evt
= target
.GetType ().GetEvent (eventName
);
269 string usualName
= moduleName
+ "_" + eventName
;
270 object methodData
= possibleEvents
[usualName
];
271 if (methodData
== null)
274 if (methodData
is MethodInfo
) {
275 AddHandler (evt
, target
, app
, (MethodInfo
) methodData
);
279 ArrayList list
= (ArrayList
) methodData
;
280 foreach (MethodInfo method
in list
)
281 AddHandler (evt
, target
, app
, method
);
285 static void AddHandler (EventInfo evt
, object target
, HttpApplication app
, MethodInfo method
)
287 int length
= method
.GetParameters ().Length
;
290 NoParamsInvoker npi
= new NoParamsInvoker (app
, method
.Name
);
291 evt
.AddEventHandler (target
, npi
.FakeDelegate
);
293 evt
.AddEventHandler (target
, Delegate
.CreateDelegate (
294 typeof (EventHandler
), app
, method
.Name
));
298 private IHttpHandler
GetPublicInstance(HttpContext context
) {
299 HttpApplication app
= null;
301 lock (_appFreePublicList
) {
302 if (_appFreePublicInstances
> 0) {
303 app
= (HttpApplication
) _appFreePublicList
.Pop();
304 _appFreePublicInstances
--;
309 // Create non-public object
310 app
= (HttpApplication
) HttpRuntime
.CreateInternalObject(_appType
);
312 app
.Startup(context
, HttpApplicationFactory
.ApplicationState
);
315 return (IHttpHandler
) app
;
318 internal void RecyclePublicInstance(HttpApplication app
) {
319 lock (_appFreePublicList
) {
320 if (_appFreePublicInstances
< _appMaxFreePublicInstances
) {
321 _appFreePublicList
.Push(app
);
322 _appFreePublicInstances
++;
333 static HttpStaticObjectsCollection
MakeStaticCollection (ArrayList list
)
335 if (list
== null || list
.Count
== 0)
338 HttpStaticObjectsCollection coll
= new HttpStaticObjectsCollection ();
339 foreach (ObjectTagBuilder tag
in list
) {
346 static internal HttpApplicationState ApplicationState
{
348 if (null == s_Factory
._state
) {
349 HttpStaticObjectsCollection app
= MakeStaticCollection (GlobalAsaxCompiler
.ApplicationObjects
);
350 HttpStaticObjectsCollection ses
= MakeStaticCollection (GlobalAsaxCompiler
.SessionObjects
);
351 s_Factory
._state
= new HttpApplicationState (app
, ses
);
354 return s_Factory
._state
;
358 internal static void EndApplication() {
362 public static void SetCustomApplication (IHttpHandler customApplication
)
364 custApplication
= customApplication
;
367 internal Type AppType
{
368 get { return _appType; }
371 internal static void SignalError(Exception exc
) {
372 // TODO: Raise an error (we probably don't have a HttpContext)