namespace System.Web.Mvc { using System; using System.Web; using System.Web.Mvc.Async; using System.Web.Routing; using System.Web.SessionState; public class MvcHttpHandler : UrlRoutingHandler, IHttpAsyncHandler, IRequiresSessionState { private static readonly object _processRequestTag = new object(); protected virtual IAsyncResult BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, object state) { HttpContextBase iHttpContext = new HttpContextWrapper(httpContext); return BeginProcessRequest(iHttpContext, callback, state); } protected internal virtual IAsyncResult BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, object state) { IHttpHandler httpHandler = GetHttpHandler(httpContext); IHttpAsyncHandler httpAsyncHandler = httpHandler as IHttpAsyncHandler; if (httpAsyncHandler != null) { // asynchronous handler BeginInvokeDelegate beginDelegate = delegate(AsyncCallback asyncCallback, object asyncState) { return httpAsyncHandler.BeginProcessRequest(HttpContext.Current, asyncCallback, asyncState); }; EndInvokeDelegate endDelegate = delegate(IAsyncResult asyncResult) { httpAsyncHandler.EndProcessRequest(asyncResult); }; return AsyncResultWrapper.Begin(callback, state, beginDelegate, endDelegate, _processRequestTag); } else { // synchronous handler Action action = delegate { httpHandler.ProcessRequest(HttpContext.Current); }; return AsyncResultWrapper.BeginSynchronous(callback, state, action, _processRequestTag); } } protected internal virtual void EndProcessRequest(IAsyncResult asyncResult) { AsyncResultWrapper.End(asyncResult, _processRequestTag); } private static IHttpHandler GetHttpHandler(HttpContextBase httpContext) { DummyHttpHandler dummyHandler = new DummyHttpHandler(); dummyHandler.PublicProcessRequest(httpContext); return dummyHandler.HttpHandler; } // synchronous code protected override void VerifyAndProcessRequest(IHttpHandler httpHandler, HttpContextBase httpContext) { if (httpHandler == null) { throw new ArgumentNullException("httpHandler"); } httpHandler.ProcessRequest(HttpContext.Current); } #region IHttpAsyncHandler Members IAsyncResult IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData) { return BeginProcessRequest(context, cb, extraData); } void IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) { EndProcessRequest(result); } #endregion // Since UrlRoutingHandler.ProcessRequest() does the heavy lifting of looking at the RouteCollection for // a matching route, we need to call into it. However, that method is also responsible for kicking off // the synchronous request, and we can't allow it to do that. The purpose of this dummy class is to run // only the lookup portion of UrlRoutingHandler.ProcessRequest(), then intercept the handler it returns // and execute it asynchronously. private sealed class DummyHttpHandler : UrlRoutingHandler { public IHttpHandler HttpHandler; public void PublicProcessRequest(HttpContextBase httpContext) { ProcessRequest(httpContext); } protected override void VerifyAndProcessRequest(IHttpHandler httpHandler, HttpContextBase httpContext) { // don't process the request, just store a reference to it HttpHandler = httpHandler; } } } }