1 namespace System.Web.Mvc {
4 using System.Web.Mvc.Async;
5 using System.Web.Routing;
6 using System.Web.SessionState;
8 public class MvcHttpHandler : UrlRoutingHandler, IHttpAsyncHandler, IRequiresSessionState {
10 private static readonly object _processRequestTag = new object();
12 protected virtual IAsyncResult BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, object state) {
13 HttpContextBase iHttpContext = new HttpContextWrapper(httpContext);
14 return BeginProcessRequest(iHttpContext, callback, state);
17 protected internal virtual IAsyncResult BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, object state) {
18 IHttpHandler httpHandler = GetHttpHandler(httpContext);
19 IHttpAsyncHandler httpAsyncHandler = httpHandler as IHttpAsyncHandler;
21 if (httpAsyncHandler != null) {
22 // asynchronous handler
23 BeginInvokeDelegate beginDelegate = delegate(AsyncCallback asyncCallback, object asyncState) {
24 return httpAsyncHandler.BeginProcessRequest(HttpContext.Current, asyncCallback, asyncState);
26 EndInvokeDelegate endDelegate = delegate(IAsyncResult asyncResult) {
27 httpAsyncHandler.EndProcessRequest(asyncResult);
29 return AsyncResultWrapper.Begin(callback, state, beginDelegate, endDelegate, _processRequestTag);
32 // synchronous handler
33 Action action = delegate {
34 httpHandler.ProcessRequest(HttpContext.Current);
36 return AsyncResultWrapper.BeginSynchronous(callback, state, action, _processRequestTag);
40 protected internal virtual void EndProcessRequest(IAsyncResult asyncResult) {
41 AsyncResultWrapper.End(asyncResult, _processRequestTag);
44 private static IHttpHandler GetHttpHandler(HttpContextBase httpContext) {
45 DummyHttpHandler dummyHandler = new DummyHttpHandler();
46 dummyHandler.PublicProcessRequest(httpContext);
47 return dummyHandler.HttpHandler;
51 protected override void VerifyAndProcessRequest(IHttpHandler httpHandler, HttpContextBase httpContext) {
52 if (httpHandler == null) {
53 throw new ArgumentNullException("httpHandler");
56 httpHandler.ProcessRequest(HttpContext.Current);
59 #region IHttpAsyncHandler Members
60 IAsyncResult IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData) {
61 return BeginProcessRequest(context, cb, extraData);
64 void IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) {
65 EndProcessRequest(result);
69 // Since UrlRoutingHandler.ProcessRequest() does the heavy lifting of looking at the RouteCollection for
70 // a matching route, we need to call into it. However, that method is also responsible for kicking off
71 // the synchronous request, and we can't allow it to do that. The purpose of this dummy class is to run
72 // only the lookup portion of UrlRoutingHandler.ProcessRequest(), then intercept the handler it returns
73 // and execute it asynchronously.
75 private sealed class DummyHttpHandler : UrlRoutingHandler {
76 public IHttpHandler HttpHandler;
78 public void PublicProcessRequest(HttpContextBase httpContext) {
79 ProcessRequest(httpContext);
82 protected override void VerifyAndProcessRequest(IHttpHandler httpHandler, HttpContextBase httpContext) {
83 // don't process the request, just store a reference to it
84 HttpHandler = httpHandler;