2 // System.Web.HttpApplication.cs
5 // Miguel de Icaza (miguel@novell.com)
6 // Gonzalo Paniagua (gonzalo@ximian.com)
9 // Copyright (C) 2005 Novell, Inc (http://www.novell.com)
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 // The Application Processing Pipeline.
32 // The Http application pipeline implemented in this file is a
33 // beautiful thing. The application pipeline invokes a number of
34 // hooks at various stages of the processing of a request. These
35 // hooks can be either synchronous or can be asynchronous.
37 // The pipeline must ensure that every step is completed before
38 // moving to the next step. A trivial thing for synchronous
39 // hooks, but asynchronous hooks introduce an extra layer of
40 // complexity: when the hook is invoked, the thread must
41 // relinquish its control so that the thread can be reused in
42 // another operation while waiting.
44 // To implement this functionality we used C# iterators manually;
45 // we drive the pipeline by executing the various hooks from the
46 // `RunHooks' routine which is an enumerator that will yield the
47 // value `false' if execution must proceed or `true' if execution
50 // By yielding values we can suspend execution of RunHooks.
52 // Special attention must be given to `in_begin' and `must_yield'
53 // variables. These are used in the case that an async hook
54 // completes synchronously as its important to not yield in that
55 // case or we would hang.
57 // Many of Mono modules used to be declared async, but they would
58 // actually be completely synchronous, this might resurface in the
59 // future with other modules.
66 using System.Collections;
67 using System.ComponentModel;
68 using System.Configuration;
69 using System.Diagnostics;
70 using System.Globalization;
71 using System.Reflection;
72 using System.Security.Permissions;
73 using System.Security.Principal;
74 using System.Threading;
75 using System.Web.Caching;
76 using System.Web.Configuration;
77 using System.Web.SessionState;
84 namespace System.Web {
87 [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
88 [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
91 public class HttpApplication : IHttpAsyncHandler, IHttpHandler, IComponent, IDisposable
93 static readonly object disposedEvent = new object ();
94 static readonly object errorEvent = new object ();
96 // we do this static rather than per HttpApplication because
97 // mono's perfcounters use the counter instance parameter for
98 // the process to access shared memory.
99 internal static PerformanceCounter requests_total_counter = new PerformanceCounter ("ASP.NET", "Requests Total");
101 internal static readonly string [] BinDirs = {"Bin", "bin"};
102 object this_lock = new object();
105 HttpSessionState session;
108 // The source, and the exposed API (cache).
109 HttpModuleCollection modcoll;
111 string assemblyLocation;
114 // The factory for the handler currently running.
116 IHttpHandlerFactory factory;
119 // Whether the thread culture is to be auto-set.
120 // Used only in the 2.0 profile, always false for 1.x
126 // Whether the pipeline should be stopped
128 bool stop_processing;
131 // See https://bugzilla.novell.com/show_bug.cgi?id=381971
133 bool in_application_start;
138 IEnumerator pipeline;
140 // To flag when we are done processing a request from BeginProcessRequest.
141 ManualResetEvent done;
143 // The current IAsyncResult for the running async request handler in the pipeline
144 AsyncRequestState begin_iar;
146 // Tracks the current AsyncInvocation being dispatched
147 AsyncInvoker current_ai;
149 EventHandlerList events;
150 EventHandlerList nonApplicationEvents = new EventHandlerList ();
152 // Culture and IPrincipal
153 CultureInfo app_culture;
154 CultureInfo appui_culture;
155 CultureInfo prev_app_culture;
156 CultureInfo prev_appui_culture;
157 IPrincipal prev_user;
159 static string binDirectory;
163 const string initialization_exception_key = "System.Web.HttpApplication.initialization_exception";
164 static Exception initialization_exception {
165 get { return (Exception) AppDomain.CurrentDomain.GetData (initialization_exception_key); }
166 set { AppDomain.CurrentDomain.SetData (initialization_exception_key, value); }
169 static Exception initialization_exception;
171 bool removeConfigurationFromCache;
173 bool fullInitComplete = false;
176 // These are used to detect the case where the EndXXX method is invoked
177 // from within the BeginXXXX delegate, so we detect whether we kick the
178 // pipeline from here, or from the the RunHook routine
183 public virtual event EventHandler Disposed {
184 add { nonApplicationEvents.AddHandler (disposedEvent, value); }
185 remove { nonApplicationEvents.RemoveHandler (disposedEvent, value); }
188 public virtual event EventHandler Error {
189 add { nonApplicationEvents.AddHandler (errorEvent, value); }
190 remove { nonApplicationEvents.RemoveHandler (errorEvent, value); }
193 public HttpApplication ()
195 done = new ManualResetEvent (false);
198 internal void InitOnce (bool full_init)
205 HttpModulesSection modules;
206 modules = (HttpModulesSection) WebConfigurationManager.GetWebApplicationSection ("system.web/httpModules");
208 ModulesConfiguration modules;
210 modules = (ModulesConfiguration) HttpContext.GetAppConfig ("system.web/httpModules");
213 HttpContext saved = HttpContext.Current;
214 HttpContext.Current = new HttpContext (new System.Web.Hosting.SimpleWorkerRequest ("", "", new StringWriter()));
215 modcoll = modules.LoadModules (this);
216 HttpContext.Current = saved;
219 HttpApplicationFactory.AttachEvents (this);
221 fullInitComplete = true;
226 internal bool InApplicationStart {
227 get { return in_application_start; }
228 set { in_application_start = value; }
231 internal string AssemblyLocation {
233 if (assemblyLocation == null)
234 assemblyLocation = GetType ().Assembly.Location;
235 return assemblyLocation;
240 internal static Exception InitializationException {
241 get { return initialization_exception; }
246 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
247 public HttpApplicationState Application {
249 return HttpApplicationFactory.ApplicationState;
254 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
255 public HttpContext Context {
261 protected EventHandlerList Events {
264 events = new EventHandlerList ();
271 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
272 public HttpModuleCollection Modules {
273 [AspNetHostingPermission (SecurityAction.Demand, Level = AspNetHostingPermissionLevel.High)]
277 modcoll = new HttpModuleCollection ();
285 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
286 public HttpRequest Request {
289 throw new HttpException (Locale.GetText ("No context is available."));
291 if (false == HttpApplicationFactory.ContextAvailable)
292 throw new HttpException (Locale.GetText ("Request is not available in this context."));
294 return context.Request;
299 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
300 public HttpResponse Response {
303 throw new HttpException (Locale.GetText ("No context is available."));
305 if (false == HttpApplicationFactory.ContextAvailable)
306 throw new HttpException (Locale.GetText ("Response is not available in this context."));
308 return context.Response;
313 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
314 public HttpServerUtility Server {
317 return context.Server;
320 // This is so we can get the Server and call a few methods
321 // which are not context sensitive, see HttpServerUtilityTest
323 return new HttpServerUtility ((HttpContext) null);
328 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
329 public HttpSessionState Session {
331 // Only used for Session_End
336 throw new HttpException (Locale.GetText ("No context is available."));
338 HttpSessionState ret = context.Session;
340 throw new HttpException (Locale.GetText ("Session state is not available in the context."));
347 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
351 public virtual ISite Site {
363 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
364 public IPrincipal User {
367 throw new HttpException (Locale.GetText ("No context is available."));
368 if (context.User == null)
369 throw new HttpException (Locale.GetText ("No currently authenticated user."));
375 static object PreSendRequestHeadersEvent = new object ();
376 public event EventHandler PreSendRequestHeaders
378 add { AddEventHandler (PreSendRequestHeadersEvent, value); }
379 remove { RemoveEventHandler (PreSendRequestHeadersEvent, value); }
382 internal void TriggerPreSendRequestHeaders ()
384 EventHandler handler = Events [PreSendRequestHeadersEvent] as EventHandler;
386 handler (this, EventArgs.Empty);
389 static object PreSendRequestContentEvent = new object ();
390 public event EventHandler PreSendRequestContent
392 add { AddEventHandler (PreSendRequestContentEvent, value); }
393 remove { RemoveEventHandler (PreSendRequestContentEvent, value); }
396 internal void TriggerPreSendRequestContent ()
398 EventHandler handler = Events [PreSendRequestContentEvent] as EventHandler;
400 handler (this, EventArgs.Empty);
403 static object AcquireRequestStateEvent = new object ();
404 public event EventHandler AcquireRequestState
406 add { AddEventHandler (AcquireRequestStateEvent, value); }
407 remove { RemoveEventHandler (AcquireRequestStateEvent, value); }
410 public void AddOnAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
412 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
413 AcquireRequestState += new EventHandler (invoker.Invoke);
416 static object AuthenticateRequestEvent = new object ();
417 public event EventHandler AuthenticateRequest
419 add { AddEventHandler (AuthenticateRequestEvent, value); }
420 remove { RemoveEventHandler (AuthenticateRequestEvent, value); }
423 public void AddOnAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh)
425 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
426 AuthenticateRequest += new EventHandler (invoker.Invoke);
429 static object AuthorizeRequestEvent = new object ();
430 public event EventHandler AuthorizeRequest
432 add { AddEventHandler (AuthorizeRequestEvent, value); }
433 remove { RemoveEventHandler (AuthorizeRequestEvent, value); }
436 public void AddOnAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh)
438 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
439 AuthorizeRequest += new EventHandler (invoker.Invoke);
442 static object BeginRequestEvent = new object ();
443 public event EventHandler BeginRequest
446 // See https://bugzilla.novell.com/show_bug.cgi?id=381971
447 if (InApplicationStart)
449 AddEventHandler (BeginRequestEvent, value);
452 if (InApplicationStart)
454 RemoveEventHandler (BeginRequestEvent, value);
458 public void AddOnBeginRequestAsync (BeginEventHandler bh, EndEventHandler eh)
460 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
461 BeginRequest += new EventHandler (invoker.Invoke);
464 static object EndRequestEvent = new object ();
465 public event EventHandler EndRequest
468 // See https://bugzilla.novell.com/show_bug.cgi?id=381971
469 if (InApplicationStart)
471 AddEventHandler (EndRequestEvent, value);
474 if (InApplicationStart)
476 RemoveEventHandler (EndRequestEvent, value);
480 public void AddOnEndRequestAsync (BeginEventHandler bh, EndEventHandler eh)
482 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
483 EndRequest += new EventHandler (invoker.Invoke);
486 static object PostRequestHandlerExecuteEvent = new object ();
487 public event EventHandler PostRequestHandlerExecute
489 add { AddEventHandler (PostRequestHandlerExecuteEvent, value); }
490 remove { RemoveEventHandler (PostRequestHandlerExecuteEvent, value); }
493 public void AddOnPostRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh)
495 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
496 PostRequestHandlerExecute += new EventHandler (invoker.Invoke);
499 static object PreRequestHandlerExecuteEvent = new object ();
500 public event EventHandler PreRequestHandlerExecute
502 add { AddEventHandler (PreRequestHandlerExecuteEvent, value); }
503 remove { RemoveEventHandler (PreRequestHandlerExecuteEvent, value); }
506 public void AddOnPreRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh)
508 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
509 PreRequestHandlerExecute += new EventHandler (invoker.Invoke);
512 static object ReleaseRequestStateEvent = new object ();
513 public event EventHandler ReleaseRequestState
515 add { AddEventHandler (ReleaseRequestStateEvent, value); }
516 remove { RemoveEventHandler (ReleaseRequestStateEvent, value); }
519 public void AddOnReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
521 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
522 ReleaseRequestState += new EventHandler (invoker.Invoke);
525 static object ResolveRequestCacheEvent = new object ();
526 public event EventHandler ResolveRequestCache
528 add { AddEventHandler (ResolveRequestCacheEvent, value); }
529 remove { RemoveEventHandler (ResolveRequestCacheEvent, value); }
532 public void AddOnResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
534 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
535 ResolveRequestCache += new EventHandler (invoker.Invoke);
538 static object UpdateRequestCacheEvent = new object ();
539 public event EventHandler UpdateRequestCache
541 add { AddEventHandler (UpdateRequestCacheEvent, value); }
542 remove { RemoveEventHandler (UpdateRequestCacheEvent, value); }
545 public void AddOnUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
547 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
548 UpdateRequestCache += new EventHandler (invoker.Invoke);
552 static object PostAuthenticateRequestEvent = new object ();
553 public event EventHandler PostAuthenticateRequest
555 add { AddEventHandler (PostAuthenticateRequestEvent, value); }
556 remove { RemoveEventHandler (PostAuthenticateRequestEvent, value); }
559 public void AddOnPostAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh)
561 AddOnPostAuthenticateRequestAsync (bh, eh, null);
564 public void AddOnPostAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
566 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
567 PostAuthenticateRequest += new EventHandler (invoker.Invoke);
570 static object PostAuthorizeRequestEvent = new object ();
571 public event EventHandler PostAuthorizeRequest
573 add { AddEventHandler (PostAuthorizeRequestEvent, value); }
574 remove { RemoveEventHandler (PostAuthorizeRequestEvent, value); }
577 public void AddOnPostAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh)
579 AddOnPostAuthorizeRequestAsync (bh, eh, null);
582 public void AddOnPostAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
584 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
585 PostAuthorizeRequest += new EventHandler (invoker.Invoke);
588 static object PostResolveRequestCacheEvent = new object ();
589 public event EventHandler PostResolveRequestCache
591 add { AddEventHandler (PostResolveRequestCacheEvent, value); }
592 remove { RemoveEventHandler (PostResolveRequestCacheEvent, value); }
595 public void AddOnPostResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
597 AddOnPostResolveRequestCacheAsync (bh, eh, null);
600 public void AddOnPostResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
602 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
603 PostResolveRequestCache += new EventHandler (invoker.Invoke);
606 static object PostMapRequestHandlerEvent = new object ();
607 public event EventHandler PostMapRequestHandler
609 add { AddEventHandler (PostMapRequestHandlerEvent, value); }
610 remove { RemoveEventHandler (PostMapRequestHandlerEvent, value); }
613 public void AddOnPostMapRequestHandlerAsync (BeginEventHandler bh, EndEventHandler eh)
615 AddOnPostMapRequestHandlerAsync (bh, eh, null);
618 public void AddOnPostMapRequestHandlerAsync (BeginEventHandler bh, EndEventHandler eh, object data)
620 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
621 PostMapRequestHandler += new EventHandler (invoker.Invoke);
624 static object PostAcquireRequestStateEvent = new object ();
625 public event EventHandler PostAcquireRequestState
627 add { AddEventHandler (PostAcquireRequestStateEvent, value); }
628 remove { RemoveEventHandler (PostAcquireRequestStateEvent, value); }
631 public void AddOnPostAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
633 AddOnPostAcquireRequestStateAsync (bh, eh, null);
636 public void AddOnPostAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
638 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
639 PostAcquireRequestState += new EventHandler (invoker.Invoke);
642 static object PostReleaseRequestStateEvent = new object ();
643 public event EventHandler PostReleaseRequestState
645 add { AddEventHandler (PostReleaseRequestStateEvent, value); }
646 remove { RemoveEventHandler (PostReleaseRequestStateEvent, value); }
649 public void AddOnPostReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
651 AddOnPostReleaseRequestStateAsync (bh, eh, null);
654 public void AddOnPostReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
656 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
657 PostReleaseRequestState += new EventHandler (invoker.Invoke);
660 static object PostUpdateRequestCacheEvent = new object ();
661 public event EventHandler PostUpdateRequestCache
663 add { AddEventHandler (PostUpdateRequestCacheEvent, value); }
664 remove { RemoveEventHandler (PostUpdateRequestCacheEvent, value); }
667 public void AddOnPostUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
669 AddOnPostUpdateRequestCacheAsync (bh, eh, null);
672 public void AddOnPostUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
674 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
675 PostUpdateRequestCache += new EventHandler (invoker.Invoke);
679 // The new overloads that take a data parameter
681 public void AddOnAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
683 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
684 AcquireRequestState += new EventHandler (invoker.Invoke);
687 public void AddOnAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
689 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
690 AuthenticateRequest += new EventHandler (invoker.Invoke);
693 public void AddOnAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
695 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
696 AuthorizeRequest += new EventHandler (invoker.Invoke);
699 public void AddOnBeginRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
701 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
702 BeginRequest += new EventHandler (invoker.Invoke);
705 public void AddOnEndRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
707 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
708 EndRequest += new EventHandler (invoker.Invoke);
711 public void AddOnPostRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh, object data)
713 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
714 PostRequestHandlerExecute += new EventHandler (invoker.Invoke);
717 public void AddOnPreRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh, object data)
719 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
720 PreRequestHandlerExecute += new EventHandler (invoker.Invoke);
723 public void AddOnReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
725 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
726 ReleaseRequestState += new EventHandler (invoker.Invoke);
729 public void AddOnResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
731 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
732 ResolveRequestCache += new EventHandler (invoker.Invoke);
735 public void AddOnUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
737 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
738 UpdateRequestCache += new EventHandler (invoker.Invoke);
742 // They are for use with the IIS7 integrated mode, but have been added for
744 static object LogRequestEvent = new object ();
745 public event EventHandler LogRequest
747 add { AddEventHandler (LogRequestEvent, value); }
748 remove { RemoveEventHandler (LogRequestEvent, value); }
751 public void AddOnLogRequestAsync (BeginEventHandler bh, EndEventHandler eh)
753 AddOnLogRequestAsync (bh, eh, null);
756 public void AddOnLogRequestAsync (BeginEventHandler beginHandler, EndEventHandler endHandler, object state)
758 AsyncInvoker invoker = new AsyncInvoker (beginHandler, endHandler, state);
759 LogRequest += new EventHandler (invoker.Invoke);
762 static object MapRequestHandlerEvent = new object ();
763 public event EventHandler MapRequestHandler
765 add { AddEventHandler (MapRequestHandlerEvent, value); }
766 remove { RemoveEventHandler (MapRequestHandlerEvent, value); }
769 public void AddOnMapRequestHandlerAsync (BeginEventHandler bh, EndEventHandler eh)
771 AddOnMapRequestHandlerAsync (bh, eh, null);
774 public void AddOnMapRequestHandlerAsync (BeginEventHandler beginHandler, EndEventHandler endHandler, object state)
776 AsyncInvoker invoker = new AsyncInvoker (beginHandler, endHandler, state);
777 MapRequestHandler += new EventHandler (invoker.Invoke);
780 static object PostLogRequestEvent = new object ();
781 public event EventHandler PostLogRequest
783 add { AddEventHandler (PostLogRequestEvent, value); }
784 remove { RemoveEventHandler (PostLogRequestEvent, value); }
787 public void AddOnPostLogRequestAsync (BeginEventHandler bh, EndEventHandler eh)
789 AddOnPostLogRequestAsync (bh, eh, null);
792 public void AddOnPostLogRequestAsync (BeginEventHandler beginHandler, EndEventHandler endHandler, object state)
794 AsyncInvoker invoker = new AsyncInvoker (beginHandler, endHandler, state);
795 PostLogRequest += new EventHandler (invoker.Invoke);
800 internal event EventHandler DefaultAuthentication;
802 void AddEventHandler (object key, EventHandler handler)
804 if (fullInitComplete)
807 Events.AddHandler (key, handler);
810 void RemoveEventHandler (object key, EventHandler handler)
812 if (fullInitComplete)
815 Events.RemoveHandler (key, handler);
819 // Bypass all the event on the Http pipeline and go directly to EndRequest
821 public void CompleteRequest ()
823 stop_processing = true;
826 internal bool RequestCompleted {
827 set { stop_processing = value; }
830 internal void DisposeInternal ()
834 if (modcoll != null) {
835 for (int i = modcoll.Count - 1; i >= 0; i--) {
836 modcoll.Get (i).Dispose ();
842 EventHandler eh = nonApplicationEvents [disposedEvent] as EventHandler;
844 eh (this, EventArgs.Empty);
850 public virtual void Dispose ()
854 public virtual string GetVaryByCustomString (HttpContext context, string custom)
856 if (custom == null) // Sigh
857 throw new NullReferenceException ();
859 if (0 == String.Compare (custom, "browser", true, CultureInfo.InvariantCulture))
860 return context.Request.Browser.Type;
866 // If we catch an error, queue this error
868 void ProcessError (Exception e)
870 bool first = context.Error == null;
871 context.AddError (e);
873 EventHandler eh = nonApplicationEvents [errorEvent] as EventHandler;
876 eh (this, EventArgs.Empty);
877 } catch (ThreadAbortException taex){
878 context.ClearError ();
879 if (FlagEnd.Value == taex.ExceptionState)
880 // This happens on Redirect() or End()
881 Thread.ResetAbort ();
883 // This happens on Thread.Abort()
884 context.AddError (taex);
885 } catch (Exception ee){
886 context.AddError (ee);
890 stop_processing = true;
892 // we want to remove configuration from the cache in case of
893 // invalid resource not exists to prevent DOS attack.
894 HttpException httpEx = e as HttpException;
895 if (httpEx != null && httpEx.GetHttpCode () == 404) {
896 removeConfigurationFromCache = true;
902 // Ticks the clock: next step on the pipeline.
904 internal void Tick ()
908 if (context.Error is UnifyRequestException) {
909 Exception ex = context.Error.InnerException;
910 context.ClearError ();
911 vmw.common.TypeUtils.Throw (ex);
915 if (pipeline.MoveNext ()){
916 if ((bool)pipeline.Current)
921 catch (Exception ex) {
922 if (ex is ThreadAbortException &&
923 ((ThreadAbortException) ex).ExceptionState == FlagEnd.Value)
925 if (context.WorkerRequest is IHttpUnifyWorkerRequest) {
926 context.ClearError ();
927 context.AddError (new UnifyRequestException (ex));
934 } catch (ThreadAbortException taex) {
935 object obj = taex.ExceptionState;
936 Thread.ResetAbort ();
937 stop_processing = true;
938 if (obj is StepTimeout)
939 ProcessError (new HttpException ("The request timed out."));
941 context.ClearError ();
942 if (FlagEnd.Value != obj)
943 context.AddError (taex);
947 } catch (Exception e) {
948 stop_processing = true;
963 // Invoked when our async callback called from RunHooks completes,
964 // we restart the pipeline here.
966 void async_callback_completed_cb (IAsyncResult ar)
968 if (current_ai.end != null){
971 } catch (Exception e) {
979 void async_handler_complete_cb (IAsyncResult ar)
981 IHttpAsyncHandler async_handler = ar != null ? ar.AsyncState as IHttpAsyncHandler : null;
984 if (async_handler != null)
985 async_handler.EndProcessRequest (ar);
986 } catch (Exception e){
994 // This enumerator yields whether processing must be stopped:
995 // true: processing of the pipeline must be stopped
996 // false: processing of the pipeline must not be stopped
998 IEnumerable RunHooks (Delegate list)
1000 Delegate [] delegates = list.GetInvocationList ();
1002 foreach (EventHandler d in delegates){
1003 if (d.Target != null && (d.Target is AsyncInvoker)){
1004 current_ai = (AsyncInvoker) d.Target;
1009 context.BeginTimeoutPossible ();
1010 current_ai.begin (this, EventArgs.Empty, async_callback_completed_cb, current_ai.data);
1013 context.EndTimeoutPossible ();
1017 // If things are still moving forward, yield this
1021 yield return stop_processing;
1022 else if (stop_processing)
1026 context.BeginTimeoutPossible ();
1027 d (this, EventArgs.Empty);
1029 context.EndTimeoutPossible ();
1031 if (stop_processing)
1037 static void FinalErrorWrite (HttpResponse response, string error)
1040 response.Write (error);
1041 response.Flush (true);
1049 if (context.Error == null){
1051 context.Response.Flush (true);
1052 } catch (Exception e){
1053 context.AddError (e);
1057 Exception error = context.Error;
1059 HttpResponse response = context.Response;
1061 if (!response.HeadersSent){
1062 response.ClearHeaders ();
1063 response.ClearContent ();
1065 if (error is HttpException){
1066 response.StatusCode = ((HttpException)error).GetHttpCode ();
1068 error = new HttpException ("", error);
1069 response.StatusCode = 500;
1071 HttpException httpEx = (HttpException) error;
1072 if (!RedirectCustomError (ref httpEx))
1073 FinalErrorWrite (response, httpEx.GetHtmlErrorMessage ());
1075 response.Flush (true);
1077 if (!(error is HttpException))
1078 error = new HttpException ("", error);
1079 FinalErrorWrite (response, ((HttpException) error).GetHtmlErrorMessage ());
1086 // Invoked at the end of the pipeline execution
1088 void PipelineDone ()
1091 EventHandler handler = Events [EndRequestEvent] as EventHandler;
1092 if (handler != null)
1093 handler (this, EventArgs.Empty);
1094 } catch (Exception e){
1100 } catch (ThreadAbortException taex) {
1101 ProcessError (taex);
1102 Thread.ResetAbort ();
1103 } catch (Exception e) {
1104 Console.WriteLine ("Internal error: OutputPage threw an exception " + e);
1106 context.WorkerRequest.EndOfRequest();
1107 if (factory != null && context.Handler != null){
1108 factory.ReleaseHandler (context.Handler);
1109 context.Handler = null;
1113 context.PopHandler ();
1115 // context = null; -> moved to PostDone
1121 if (begin_iar != null)
1122 begin_iar.Complete ();
1126 requests_total_counter.Increment ();
1136 public Tim (string name) {
1140 public string Name {
1141 get { return name; }
1142 set { name = value; }
1145 public void Start () {
1146 start = DateTime.UtcNow;
1149 public void Stop () {
1150 Console.WriteLine ("{0}: {1}ms", name, (DateTime.UtcNow - start).TotalMilliseconds);
1155 [Conditional ("PIPELINE_TIMER")]
1156 void StartTimer (string name)
1164 [Conditional ("PIPELINE_TIMER")]
1171 // Events fired as described in `Http Runtime Support, HttpModules,
1172 // Handling Public Events'
1174 IEnumerator Pipeline ()
1176 Delegate eventHandler;
1177 if (stop_processing)
1181 context.MapRequestHandlerDone = false;
1183 StartTimer ("BeginRequest");
1184 eventHandler = Events [BeginRequestEvent];
1185 if (eventHandler != null) {
1186 foreach (bool stop in RunHooks (eventHandler))
1191 StartTimer ("AuthenticateRequest");
1192 eventHandler = Events [AuthenticateRequestEvent];
1193 if (eventHandler != null)
1194 foreach (bool stop in RunHooks (eventHandler))
1198 StartTimer ("DefaultAuthentication");
1199 if (DefaultAuthentication != null)
1200 foreach (bool stop in RunHooks (DefaultAuthentication))
1205 StartTimer ("PostAuthenticateRequest");
1206 eventHandler = Events [PostAuthenticateRequestEvent];
1207 if (eventHandler != null)
1208 foreach (bool stop in RunHooks (eventHandler))
1212 StartTimer ("AuthorizeRequest");
1213 eventHandler = Events [AuthorizeRequestEvent];
1214 if (eventHandler != null)
1215 foreach (bool stop in RunHooks (eventHandler))
1219 StartTimer ("PostAuthorizeRequest");
1220 eventHandler = Events [PostAuthorizeRequestEvent];
1221 if (eventHandler != null)
1222 foreach (bool stop in RunHooks (eventHandler))
1227 StartTimer ("ResolveRequestCache");
1228 eventHandler = Events [ResolveRequestCacheEvent];
1229 if (eventHandler != null)
1230 foreach (bool stop in RunHooks (eventHandler))
1235 StartTimer ("PostResolveRequestCache");
1236 eventHandler = Events [PostResolveRequestCacheEvent];
1237 if (eventHandler != null)
1238 foreach (bool stop in RunHooks (eventHandler))
1242 StartTimer ("MapRequestHandler");
1243 // As per http://msdn2.microsoft.com/en-us/library/bb470252(VS.90).aspx
1244 eventHandler = Events [MapRequestHandlerEvent];
1245 if (eventHandler != null)
1246 foreach (bool stop in RunHooks (eventHandler))
1249 context.MapRequestHandlerDone = true;
1252 StartTimer ("GetHandler");
1253 // Obtain the handler for the request.
1254 IHttpHandler handler = null;
1256 handler = GetHandler (context, context.Request.CurrentExecutionFilePath);
1257 context.Handler = handler;
1259 context.PushHandler (handler);
1261 } catch (FileNotFoundException fnf){
1263 Console.WriteLine ("$$$$$$$$$$:Sys.Web Pipeline");
1264 Console.WriteLine (fnf.ToString ());
1266 if (context.Request.IsLocal)
1267 ProcessError (new HttpException (404, String.Format ("File not found {0}", fnf.FileName), fnf, context.Request.FilePath));
1269 ProcessError (new HttpException (404, "File not found: " + Path.GetFileName (fnf.FileName), context.Request.FilePath));
1270 } catch (DirectoryNotFoundException dnf){
1271 if (!context.Request.IsLocal)
1272 dnf = null; // Do not "leak" real path information
1273 ProcessError (new HttpException (404, "Directory not found", dnf));
1274 } catch (Exception e) {
1279 if (stop_processing)
1283 StartTimer ("PostMapRequestHandler");
1284 eventHandler = Events [PostMapRequestHandlerEvent];
1285 if (eventHandler != null)
1286 foreach (bool stop in RunHooks (eventHandler))
1291 StartTimer ("AcquireRequestState");
1292 eventHandler = Events [AcquireRequestStateEvent];
1293 if (eventHandler != null){
1294 foreach (bool stop in RunHooks (eventHandler))
1300 StartTimer ("PostAcquireRequestState");
1301 eventHandler = Events [PostAcquireRequestStateEvent];
1302 if (eventHandler != null){
1303 foreach (bool stop in RunHooks (eventHandler))
1310 // From this point on, we need to ensure that we call
1311 // ReleaseRequestState, so the code below jumps to
1312 // `release:' to guarantee it rather than yielding.
1314 StartTimer ("PreRequestHandlerExecute");
1315 eventHandler = Events [PreRequestHandlerExecuteEvent];
1316 if (eventHandler != null)
1317 foreach (bool stop in RunHooks (eventHandler))
1325 bool doProcessHandler = false;
1329 IHttpHandler ctxHandler = context.Handler;
1330 if (ctxHandler != null && handler != ctxHandler) {
1331 context.PopHandler ();
1332 handler = ctxHandler;
1333 context.PushHandler (handler);
1337 StartTimer ("ProcessRequest");
1339 context.BeginTimeoutPossible ();
1340 if (handler != null){
1341 IHttpAsyncHandler async_handler = handler as IHttpAsyncHandler;
1343 if (async_handler != null){
1346 async_handler.BeginProcessRequest (context, async_handler_complete_cb, handler);
1349 handler.ProcessRequest (context);
1351 IHttpExtendedHandler extHandler=handler as IHttpExtendedHandler;
1352 doProcessHandler = extHandler != null && !extHandler.IsCompleted;
1356 if (context.Error != null)
1357 throw new TargetInvocationException(context.Error);
1360 context.EndTimeoutPossible ();
1364 if (doProcessHandler) {
1366 goto processHandler;
1370 yield return stop_processing;
1371 else if (stop_processing)
1374 // These are executed after the application has returned
1376 StartTimer ("PostRequestHandlerExecute");
1377 eventHandler = Events [PostRequestHandlerExecuteEvent];
1378 if (eventHandler != null)
1379 foreach (bool stop in RunHooks (eventHandler))
1385 StartTimer ("ReleaseRequestState");
1386 eventHandler = Events [ReleaseRequestStateEvent];
1387 if (eventHandler != null){
1388 #pragma warning disable 219
1389 foreach (bool stop in RunHooks (eventHandler)) {
1391 // Ignore the stop signal while release the state
1395 #pragma warning restore 219
1399 if (stop_processing)
1403 StartTimer ("PostReleaseRequestState");
1404 eventHandler = Events [PostReleaseRequestStateEvent];
1405 if (eventHandler != null)
1406 foreach (bool stop in RunHooks (eventHandler))
1411 StartTimer ("Filter");
1412 if (context.Error == null)
1413 context.Response.DoFilter (true);
1416 StartTimer ("UpdateRequestCache");
1417 eventHandler = Events [UpdateRequestCacheEvent];
1418 if (eventHandler != null)
1419 foreach (bool stop in RunHooks (eventHandler))
1424 StartTimer ("PostUpdateRequestCache");
1425 eventHandler = Events [PostUpdateRequestCacheEvent];
1426 if (eventHandler != null)
1427 foreach (bool stop in RunHooks (eventHandler))
1431 StartTimer ("LogRequest");
1432 eventHandler = Events [LogRequestEvent];
1433 if (eventHandler != null)
1434 foreach (bool stop in RunHooks (eventHandler))
1438 StartTimer ("PostLogRequest");
1439 eventHandler = Events [PostLogRequestEvent];
1440 if (eventHandler != null)
1441 foreach (bool stop in RunHooks (eventHandler))
1445 StartTimer ("PipelineDone");
1451 internal CultureInfo GetThreadCulture (HttpRequest request, CultureInfo culture, bool isAuto)
1456 CultureInfo ret = null;
1457 string[] languages = request.UserLanguages;
1459 if (languages != null && languages.Length > 0)
1460 ret = CultureInfo.CreateSpecificCulture (languages[0]);
1477 GlobalizationSection cfg;
1478 cfg = (GlobalizationSection) WebConfigurationManager.GetSection ("system.web/globalization");
1479 app_culture = cfg.GetCulture ();
1480 autoCulture = cfg.IsAutoCulture;
1481 appui_culture = cfg.GetUICulture ();
1482 autoUICulture = cfg.IsAutoUICulture;
1484 GlobalizationConfiguration cfg;
1485 cfg = GlobalizationConfiguration.GetInstance (null);
1487 app_culture = cfg.Culture;
1488 autoCulture = false; // to hush the warning
1489 appui_culture = cfg.UICulture;
1490 autoUICulture = false; // to hush the warning
1495 context.StartTimeoutTimer ();
1497 Thread th = Thread.CurrentThread;
1498 if (app_culture != null) {
1499 prev_app_culture = th.CurrentCulture;
1500 CultureInfo new_app_culture = GetThreadCulture (Request, app_culture, autoCulture);
1501 if (!new_app_culture.Equals (CultureInfo.InvariantCulture))
1502 th.CurrentCulture = new_app_culture;
1505 if (appui_culture != null) {
1506 prev_appui_culture = th.CurrentUICulture;
1507 CultureInfo new_app_culture = GetThreadCulture (Request, appui_culture, autoUICulture);
1508 if (!new_app_culture.Equals (CultureInfo.InvariantCulture))
1509 th.CurrentUICulture = new_app_culture;
1513 prev_user = Thread.CurrentPrincipal;
1520 if (removeConfigurationFromCache) {
1521 WebConfigurationManager.RemoveConfigurationFromCache (context);
1522 removeConfigurationFromCache = false;
1525 Thread th = Thread.CurrentThread;
1527 if (Thread.CurrentPrincipal != prev_user)
1528 Thread.CurrentPrincipal = prev_user;
1530 if (prev_appui_culture != null && prev_appui_culture != th.CurrentUICulture)
1531 th.CurrentUICulture = prev_appui_culture;
1532 if (prev_app_culture != null && prev_app_culture != th.CurrentCulture)
1533 th.CurrentCulture = prev_app_culture;
1536 if (context == null)
1537 context = HttpContext.Current;
1538 context.StopTimeoutTimer ();
1540 context.Request.ReleaseResources ();
1541 context.Response.ReleaseResources ();
1544 HttpContext.Current = null;
1547 void Start (object x)
1549 CultureInfo[] cultures = x as CultureInfo[];
1550 if (cultures != null && cultures.Length == 2) {
1551 Thread ct = Thread.CurrentThread;
1552 ct.CurrentCulture = cultures [0];
1553 ct.CurrentUICulture = cultures [1];
1558 } catch (Exception e) {
1560 initialization_exception = e;
1562 FinalErrorWrite (context.Response, new HttpException ("", e).GetHtmlErrorMessage ());
1567 HttpContext.Current = Context;
1569 pipeline = Pipeline ();
1573 const string HANDLER_CACHE = "@@HttpHandlerCache@@";
1575 internal static Hashtable GetHandlerCache ()
1577 Cache cache = HttpRuntime.InternalCache;
1578 Hashtable ret = cache [HANDLER_CACHE] as Hashtable;
1581 ret = new Hashtable ();
1582 cache.Insert (HANDLER_CACHE, ret);
1588 internal static void ClearHandlerCache ()
1590 Hashtable cache = GetHandlerCache ();
1594 object LocateHandler (HttpRequest req, string verb, string url)
1596 Hashtable cache = GetHandlerCache ();
1597 string id = String.Concat (verb, url);
1598 object ret = cache [id];
1605 HttpHandlersSection httpHandlersSection = WebConfigurationManager.GetSection ("system.web/httpHandlers", req.Path, req.Context) as HttpHandlersSection;
1606 ret = httpHandlersSection.LocateHandler (verb, url, out allowCache);
1608 HandlerFactoryConfiguration factory_config = (HandlerFactoryConfiguration) HttpContext.GetAppConfig ("system.web/httpHandlers");
1609 ret = factory_config.LocateHandler (verb, url, out allowCache);
1612 IHttpHandler handler = ret as IHttpHandler;
1613 if (allowCache && handler != null && handler.IsReusable)
1619 internal IHttpHandler GetHandler (HttpContext context, string url)
1621 return GetHandler (context, url, false);
1624 // Used by HttpServerUtility.Execute
1625 internal IHttpHandler GetHandler (HttpContext context, string url, bool ignoreContextHandler)
1627 if (!ignoreContextHandler && context.Handler != null)
1628 return context.Handler;
1630 HttpRequest request = context.Request;
1631 string verb = request.RequestType;
1633 IHttpHandler handler = null;
1634 object o = LocateHandler (request, verb, url);
1636 factory = o as IHttpHandlerFactory;
1637 if (factory == null) {
1638 handler = (IHttpHandler) o;
1640 handler = factory.GetHandler (context, verb, url, request.MapPath (url));
1646 void IHttpHandler.ProcessRequest (HttpContext context)
1649 this.context = context;
1657 // This is used by FireOnAppStart, when we init the application
1658 // as the context is required to be set at that point (the user
1659 // might call methods that require it on that hook).
1661 internal void SetContext (HttpContext context)
1663 this.context = context;
1666 internal void SetSession (HttpSessionState session)
1668 this.session = session;
1671 IAsyncResult IHttpAsyncHandler.BeginProcessRequest (HttpContext context, AsyncCallback cb, object extraData)
1673 this.context = context;
1676 begin_iar = new AsyncRequestState (done, cb, extraData);
1678 CultureInfo[] cultures = new CultureInfo [2];
1679 cultures [0] = Thread.CurrentThread.CurrentCulture;
1680 cultures [1] = Thread.CurrentThread.CurrentUICulture;
1685 if (Thread.CurrentThread.IsThreadPoolThread)
1689 ThreadPool.QueueUserWorkItem (new WaitCallback (Start), cultures);
1694 void IHttpAsyncHandler.EndProcessRequest (IAsyncResult result)
1700 if (!result.IsCompleted)
1701 result.AsyncWaitHandle.WaitOne ();
1705 public virtual void Init ()
1709 bool IHttpHandler.IsReusable {
1716 internal void ClearError ()
1718 context.ClearError ();
1721 bool RedirectErrorPage (string error_page)
1723 if (context.Request.QueryString ["aspxerrorpath"] != null)
1726 Response.Redirect (error_page + "?aspxerrorpath=" + Request.Path, false);
1730 bool RedirectCustomError (ref HttpException httpEx)
1733 if (!context.IsCustomErrorEnabledUnsafe)
1737 CustomErrorsSection config = (CustomErrorsSection)WebConfigurationManager.GetSection ("system.web/customErrors");
1739 CustomErrorsConfig config = null;
1741 config = (CustomErrorsConfig) context.GetConfig ("system.web/customErrors");
1745 if (config == null) {
1746 if (context.ErrorPage != null)
1747 return RedirectErrorPage (context.ErrorPage);
1753 CustomError err = config.Errors [context.Response.StatusCode.ToString()];
1754 string redirect = err == null ? null : err.Redirect;
1756 string redirect = config [context.Response.StatusCode];
1758 if (redirect == null) {
1759 redirect = context.ErrorPage;
1760 if (redirect == null)
1761 redirect = config.DefaultRedirect;
1764 if (redirect == null)
1767 return RedirectErrorPage (redirect);
1769 catch (Exception ex) {
1770 httpEx = new HttpException (500, "", ex);
1775 internal static string BinDirectory
1778 if (binDirectory == null) {
1779 AppDomainSetup setup = AppDomain.CurrentDomain.SetupInformation;
1780 string baseDir = setup.ApplicationBase;
1783 foreach (string dir in BinDirs) {
1784 bindir = Path.Combine (baseDir, dir);
1785 if (!Directory.Exists (bindir))
1787 binDirectory = bindir;
1792 return binDirectory;
1796 internal static string[] BinDirectoryAssemblies
1799 ArrayList binDlls = null;
1802 string bindir = BinDirectory;
1803 if (bindir != null) {
1804 binDlls = new ArrayList ();
1805 dlls = Directory.GetFiles (bindir, "*.dll");
1806 binDlls.AddRange (dlls);
1809 if (binDlls == null)
1810 return new string[] {};
1812 return (string[]) binDlls.ToArray (typeof (string));
1816 internal static Type LoadType (string typeName)
1818 return LoadType (typeName, false);
1821 internal static Type LoadType (string typeName, bool throwOnMissing)
1823 Type type = Type.GetType (typeName);
1828 Assembly [] assemblies = AppDomain.CurrentDomain.GetAssemblies ();
1829 foreach (Assembly ass in assemblies) {
1830 type = ass.GetType (typeName, false);
1836 IList tla = System.Web.Compilation.BuildManager.TopLevelAssemblies;
1837 if (tla != null && tla.Count > 0) {
1838 foreach (Assembly asm in tla) {
1841 type = asm.GetType (typeName, false);
1848 Exception loadException = null;
1851 type = LoadTypeFromBin (typeName);
1852 } catch (Exception ex) {
1860 throw new TypeLoadException (String.Format ("Type '{0}' cannot be found", typeName), loadException);
1865 internal static Type LoadTypeFromBin (string typeName)
1869 foreach (string s in BinDirectoryAssemblies) {
1870 Assembly binA = null;
1873 binA = Assembly.LoadFrom (s);
1874 } catch (FileLoadException) {
1877 } catch (BadImageFormatException) {
1882 type = binA.GetType (typeName, false);
1894 // Based on Fritz' Onion's AsyncRequestState class for asynchronous IHttpAsyncHandlers
1896 class AsyncRequestState : IAsyncResult {
1900 ManualResetEvent complete_event = null;
1902 internal AsyncRequestState (ManualResetEvent complete_event, AsyncCallback cb, object cb_data)
1905 this.cb_data = cb_data;
1906 this.complete_event = complete_event;
1909 internal void Complete ()
1914 // TODO: if this throws an error, we have no way of reporting it
1915 // Not really too bad, since the only failure might be
1916 // `HttpRuntime.request_processed'.
1923 complete_event.Set ();
1926 public object AsyncState {
1932 public bool CompletedSynchronously {
1938 public bool IsCompleted {
1944 public WaitHandle AsyncWaitHandle {
1946 return complete_event;
1951 #region Helper classes
1954 // A wrapper to keep track of begin/end pairs
1956 class AsyncInvoker {
1957 public BeginEventHandler begin;
1958 public EndEventHandler end;
1961 public AsyncInvoker (BeginEventHandler bh, EndEventHandler eh, object d)
1968 public AsyncInvoker (BeginEventHandler bh, EndEventHandler eh)
1974 public void Invoke (object sender, EventArgs e)
1976 throw new Exception ("This is just a dummy");