through Reflector decompile, we distribute requests to IIS w3wp.exe process after the analysis of the process by HttpRuntime understanding HttpApplication, HttpModule, HttpHandler, HttpContext generation mechanism. That we continue to learn. Net MVC URL Routing how to jump to a specified Controller / Action process.
- UrlRoutingModule
- MvcRoutingHandler
- MvcHandler
- Controller
one, UrlRoutingModule
When all HttpModule is loaded for the first HttpApplication, each in its own HttpModule Init method to achieve registration HttpApplication event HttpRequest request interception. Of course UrlRoutingModule no exception. We look UrlRoutingModule decompiled source
public class UrlRoutingModule: IHttpModule
{
/ / Fields
private static readonly object _requestDataKey = new object ();
private RouteCollection _routeCollection;
/ / Methods
protected virtual void Dispose ()
{
}
protected virtual void Init (HttpApplication application)
{
application.PostResolveRequestCache + = new EventHandler (this.OnApplicationPostResolveRequestCache);
application.PostMapRequestHandler + = new EventHandler (this.OnApplicationPostMapRequestHandler);
}
private void OnApplicationPostMapRequestHandler (object sender, EventArgs e)
{
HttpContextBase context = new HttpContextWrapper (((HttpApplication) sender). Context);
this.PostMapRequestHandler (context);
}
private void OnApplicationPostResolveRequestCache (object sender, EventArgs e)
{
HttpContextBase context = new HttpContextWrapper (((HttpApplication) sender). Context);
this.PostResolveRequestCache (context);
}
public virtual void PostMapRequestHandler (HttpContextBase context)
{
RequestData data = (RequestData) context.Items [_requestDataKey];
if (data! = null)
{
context.RewritePath (data.OriginalPath);
context.Handler = data.HttpHandler;
}
}
public virtual void PostResolveRequestCache (HttpContextBase context)
{
RouteData routeData = this.RouteCollection.GetRouteData (context);
if (routeData! = null)
{
IRouteHandler routeHandler = routeData.RouteHandler;
if (routeHandler == null)
{
throw new InvalidOperationException (string.Format (CultureInfo.CurrentUICulture, RoutingResources.UrlRoutingModule_NoRouteHandler, new object [0]));
}
if (! (routeHandler is StopRoutingHandler))
{
RequestContext requestContext = new RequestContext (context, routeData);
IHttpHandler httpHandler = routeHandler.GetHttpHandler (requestContext);
if (httpHandler == null)
{
throw new InvalidOperationException (string.Format (CultureInfo.CurrentUICulture, RoutingResources.UrlRoutingModule_NoHttpHandler, new object [] {routeHandler.GetType ()}));
}
RequestData data2 = new RequestData ();
data2.OriginalPath = context.Request.Path;
data2.HttpHandler = httpHandler;
context.Items [_requestDataKey] = data2;
context.RewritePath ("~ / UrlRouting.axd");
}
}
}
void IHttpModule.Dispose ()
{
this.Dispose ();
}
void IHttpModule.Init (HttpApplication application)
{
this.Init (application);
}
/ / Properties
public RouteCollection RouteCollection
{
get
{
if (this._routeCollection == null)
{
this._routeCollection = RouteTable.Routes;
}
return this._routeCollection;
}
set
{
this._routeCollection = value;
}
}
/ / Nested Types
private class RequestData
{
/ / Fields
[CompilerGenerated]
private IHttpHandler
[CompilerGenerated]
private string
/ / Properties
public IHttpHandler HttpHandler
{
[CompilerGenerated]
get
{
return this.
}
[CompilerGenerated]
set
{
this.
}
}
public string OriginalPath
{
[CompilerGenerated]
get
{
return this.
}
[CompilerGenerated]
set
{
this.
}
}
}
}
can see UrlRoutingModule subscribe to two HttpApplication events. Which PostResolveRequestCache than PostMapRequestHandler executed first, look PostResolveRequestCache events, starting with his first from RouteCollection get a RouteData object. And RouteCollection created by the routing table
public RouteCollection RouteCollection
{
get
{
if (this._routeCollection == null)
{
this._routeCollection = RouteTable.Routes;
}
return this._routeCollection;
}
set
{
this._routeCollection = value;
}
}
registered in Global.asax.cs route when (ie HttpApplication), has been added to RouteTable.Routes new routing information, so from their own RouteCollection HttpModule can find the corresponding request routing. RouteTable only a static collection property RouteCollection.
{
public static void RegisterRoutes (RouteCollection routes)
{
routes.IgnoreRoute ("{resource}. axd / {* pathInfo}");
routes.MapRoute (
"Default", / / Route name
"{controller} / {action} / {id}", / / URL with parameters
new {controller = "Home", action = "Index", id = UrlParameter.Optional} / / Parameter defaults
);
}
protected void Application_Start ()
{
AreaRegistration.RegisterAllAreas ();
RegisterRoutes (RouteTable.Routes);
}
}
UrlRoutingModule in PostResolveRequestCache method reads RouteData routeData <strong> = this.RouteCollection.GetRouteData (context);
RouteData is included in our registration information for each Route. Registered in the global routing time, MapRote RouteCollection extension method is used by default the MvcRouteHandler.
{
if (routes == null)
{
throw new ArgumentNullException ("routes");
}
if (url == null)
{
throw new ArgumentNullException ("url");
}
Route route2 = new Route (url, new MvcRouteHandler ());
route2.Defaults = new RouteValueDictionary (defaults);
route2.Constraints = new RouteValueDictionary (constraints);
route2.DataTokens = new RouteValueDictionary ();
Route item = route2;
if ((namespaces! = null) && (namespaces.Length> 0))
{
item.DataTokens ["Namespaces"] = namespaces;
}
routes.Add (name, item);
return item;
}
two, MvcRoutingHandler
RouteData structure in addition to the information contained in the Route and the default IRouteHandler that MvcRouteHandler.
Depending on the context in PostResolveRequestCache
compared to the routing table lookup RouteData corresponding post, and through routeHandler.GetHttpHandler (requestContext) obtained MvcHandler instance.
{
/ / Methods
protected virtual IHttpHandler GetHttpHandler (RequestContext requestContext)
{
return new MvcHandler (requestContext);
}
IHttpHandler IRouteHandler.GetHttpHandler (RequestContext requestContext)
{
return this.GetHttpHandler (requestContext);
}
}
three, MvcHandler
process can be seen from the above HttpApplication pipeline UrlRouteModule intercept each request, starting RouteCollection find HttpContext request corresponding RouteData (including MvcRouteHandler), and HttpContextBase with RouteData package for the RequestContext, by constructing among injecting MvcHandler. MvcRouteHandler really only played a role in the transition, the real work is HttpApplication pipeline led, in UrlRouteModule and MvcHandler conducted between.
UrlRouteModule in PostResolveRequestCache method to MvcHandler through MvcRouteModule get an instance,
data2.OriginalPath = context.Request.Path;
data2.HttpHandler = httpHandler;
context.Items [_requestDataKey] = data2;
context.RewritePath ("~ / UrlRouting.axd");
MvcHandler began to take over the default WebForm the HttpHandler, injected into the medium and loaded context.Items RequestData passed to the pipeline. And this context also be packaged as before the object is injected into the MvcHandler RequestContext, so we MvcHandler subsequent process can also take to the context (Page or Controller, etc.). This is UrlRouteModule RequestData internal private class, so it can not achieve it overloaded, if you want to rewrite UrlRouteModule must realize this class of their own.
Thus, to understand and then to MvcHandler MvcRouteHandler from UrlRouteModule to the creation process, but the most important question MvcHandler How does it work? UrlRouteModule intercepted HttpApplication pipeline on request, according to the routing table to find by the RouteData (Routing Information and MvcHandler), replace runs through the entire process of handling requests HttpContext HttpHandler, namely MvcHandler. The work is completed, HttpApplication pipeline to continue processing Step events that ultimately calls the ProcessRequest or BeginProcessRequest MvcHandler methods to enter to the Controller in the process.
MvcHandler trigger the process: -> HttpRuntime get to the HttpApplication-> load HttpModule, generate StepManager line and load MvcHandler-> HttpRuntime call HttpApplication.BeginProcessRequest-> HttpApplication. StepManager.ResumeSteps
-> execute StepManager in HttpApplication.StepManager._execSteps [i]. Execute -> MvcHandlers.ProcessRequest or BeginProcessRequest
Here is MvcHandlerdecompile source code, you can see that in addition to inherit IHttpHandler, also inherited IRequireSeesionState. Custom HttpHandler want to deal Session words must inherit IRequireSeesionState.
{
/ / Fields
private ControllerBuilder _controllerBuilder;
private static readonly object _processRequestTag = new object ();
[CompilerGenerated]
private static bool
[CompilerGenerated]
private RequestContext
internal static readonly string MvcVersion = GetMvcVersionString ();
public static readonly string MvcVersionHeaderName = "X-AspNetMvc-Version";
/ / Methods
public MvcHandler (RequestContext requestContext)
{
if (requestContext == null)
{
throw new ArgumentNullException ("requestContext");
}
this.RequestContext = requestContext;
}
protected internal virtual void AddVersionHeader (HttpContextBase httpContext)
{
if (! DisableMvcResponseHeader)
{
httpContext.Response.AppendHeader (MvcVersionHeaderName, MvcVersion);
}
}
protected virtual IAsyncResult BeginProcessRequest (HttpContext httpContext, AsyncCallback callback, object state)
{
HttpContextBase base2 = new HttpContextWrapper (httpContext);
return this.BeginProcessRequest (base2, callback, state);
}
protected internal virtual IAsyncResult BeginProcessRequest (HttpContextBase httpContext, AsyncCallback callback, object state)
{
BeginInvokeDelegate delegate4 = null;
EndInvokeDelegate delegate5 = null;
Action action2 = null;
IController controller;
IControllerFactory factory;
this.ProcessRequestInit (httpContext, out controller, out factory);
IAsyncController asyncController = controller as IAsyncController;
if (asyncController! = null)
{
if (delegate4 == null)
{
delegate4 = delegate (AsyncCallback asyncCallback, object asyncState) {
IAsyncResult result;
try
{
result = asyncController.BeginExecute (this.RequestContext, asyncCallback, asyncState);
}
catch
{
factory.ReleaseController (asyncController);
throw;
}
return result;
};
}
BeginInvokeDelegate beginDelegate = delegate4;
if (delegate5 == null)
{
delegate5 = delegate (IAsyncResult asyncResult) {
try
{
asyncController.EndExecute (asyncResult);
}
finally
{
factory.ReleaseController (asyncController);
}
};
}
EndInvokeDelegate endDelegate = delegate5;
SynchronizationContext synchronizationContext = SynchronizationContextUtil.GetSynchronizationContext ();
return AsyncResultWrapper.Begin (AsyncUtil.WrapCallbackForSynchronizedExecution (callback, synchronizationContext), state, beginDelegate, endDelegate, _processRequestTag);
}
if (action2 == null)
{
action2 = delegate {
try
{
controller.Execute (this.RequestContext);
}
finally
{
factory.ReleaseController (controller);
}
};
}
Action action = action2;
return AsyncResultWrapper.BeginSynchronous (callback, state, action, _processRequestTag);
}
protected internal virtual void EndProcessRequest (IAsyncResult asyncResult)
{
AsyncResultWrapper.End (asyncResult, _processRequestTag);
}
private static string GetMvcVersionString ()
{
return new AssemblyName (typeof (MvcHandler). Assembly.FullName). Version.ToString (2);
}
protected virtual void ProcessRequest (HttpContext httpContext)
{
HttpContextBase base2 = new HttpContextWrapper (httpContext);
this.ProcessRequest (base2);
}
protected internal virtual void ProcessRequest (HttpContextBase httpContext)
{
IController controller;
IControllerFactory factory;
this.ProcessRequestInit (httpContext, out controller, out factory);
try
{
controller.Execute (this.RequestContext);
}
finally
{
factory.ReleaseController (controller);
}
}
private void ProcessRequestInit (HttpContextBase httpContext, out IController controller, out IControllerFactory factory)
{
this.AddVersionHeader (httpContext);
this.RemoveOptionalRoutingParameters ();
string requiredString = this.RequestContext.RouteData.GetRequiredString ("controller");
factory = this.ControllerBuilder.GetControllerFactory ();
controller = factory.CreateController (this.RequestContext, requiredString);
if (controller == null)
{
throw new InvalidOperationException (string.Format (CultureInfo.CurrentUICulture, MvcResources.ControllerBuilder_FactoryReturnedNull, new object [] {factory.GetType (), requiredString}));
}
}
private void RemoveOptionalRoutingParameters ()
{
RouteValueDictionary values = this.RequestContext.RouteData.Values;
foreach (string str in values.Where
return (entry.Value == UrlParameter.Optional);
}). Select
return entry.Key;
}). ToArray
{
values.Remove (str);
}
}
IAsyncResult IHttpAsyncHandler.BeginProcessRequest (HttpContext context, AsyncCallback cb, object extraData)
{
return this.BeginProcessRequest (context, cb, extraData);
}
void IHttpAsyncHandler.EndProcessRequest (IAsyncResult result)
{
this.EndProcessRequest (result);
}
void IHttpHandler.ProcessRequest (HttpContext httpContext)
{
this.ProcessRequest (httpContext);
}
/ / Properties
internal ControllerBuilder ControllerBuilder
{
get
{
if (this._controllerBuilder == null)
{
this._controllerBuilder = ControllerBuilder.Current;
}
return this._controllerBuilder;
}
set
{
this._controllerBuilder = value;
}
}
public static bool DisableMvcResponseHeader
{
[CompilerGenerated]
get
{
return
}
[CompilerGenerated]
set
{
}
}
protected virtual bool IsReusable
{
get
{
return false;
}
}
public RequestContext RequestContext
{
[CompilerGenerated]
get
{
return this.
}
[CompilerGenerated]
private set
{
this.
}
}
bool IHttpHandler.IsReusable
{
get
{
return this.IsReusable;
}
}
}
four, Controller debut
look MvcHandler's ProcessRequest or BeginProcessRequest, we look at the details of the ProcessRequest method
{
IController controller;
IControllerFactory factory;
this.ProcessRequestInit (httpContext, out controller, out factory);
try
{
controller.Execute (this.RequestContext);
}
finally
{
factory.ReleaseController (controller);
}
}
private void ProcessRequestInit (HttpContextBase httpContext, out IController controller, out IControllerFactory factory)
{
this.AddVersionHeader (httpContext);
this.RemoveOptionalRoutingParameters ();
string requiredString = this.RequestContext.RouteData.GetRequiredString ("controller");
factory = this.ControllerBuilder.GetControllerFactory ();
controller = factory.CreateController (this.RequestContext, requiredString);
if (controller == null)
{
throw new InvalidOperationException (string.Format (CultureInfo.CurrentUICulture, MvcResources.ControllerBuilder_FactoryReturnedNull, new object [] {factory.GetType (), requiredString}));
}
}
mainly through ProcessRequestInit Get IControllerFactory the factory, and then through the address in the context of reflection Controller instance. That the factory where they come from?
factory = this.ControllerBuilder.GetControllerFactory (); look at this ControllerBuilder is not very familiar with? Look Global.asax.cs code
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using System.Threading;
namespace MvcApplication
{
/ / Note: For instructions on enabling IIS6 or IIS7 classic mode,
/ / visit http://go.microsoft.com/?LinkId=9394801
public class MvcApplication: System.Web.HttpApplication
{
# region
public static void RegisterRoutes (RouteCollection routes)
{
/ / routes.IgnoreRoute ("{resource}. axd / {* pathInfo}");
routes.MapRoute (
"Default", / / Route name
"{controller} / {action} / {id}", / / URL with parameters
new {controller = "Home", action = "Index", id = UrlParameter.Optional} / / Parameter defaults
);
}
# endregion
protected void Application_Start ()
{
AreaRegistration.RegisterAllAreas ();
RegisterRoutes (RouteTable.Routes);
/ / DefaultControllerFactory every time depending on the context of the Action String instance reflection Controller
/ / You can override DefaultControllerFactory achieve Controller using the IOC container instantiates work (efficiency)
ControllerBuilder.Current.SetControllerFactory (new DefaultControllerFactory ()); / / Controller reflection plant
}
}
}
generally we will put ControllerFactory injected at this time, using the default DefaultControllerFactory or their use to achieve new ControllerFactory IOC container factory.
In ControllerFactory Get Controller and perform the controller.Execute (this.RequestContext), entered the Controller of the specific business.
IController interface has only one method, ControllerBase inheritance IController, Controller also inherited achieve ControllerBase, and our specific business Controller names are based on the folder name + Controller, and inherited the Controller.
public class HomeController: Controller
now if you want to achieve a common business example: authenticate users permissions. Then we can achieve a MyController inherited base class Controller, and then the other XXXController have inherited this MyController. Of course, you can use the Filter MVC provides mechanisms (like AOP interceptors) to achieve these basic business verification, is not much more convenient than the WebForm?
Execute method is only implemented in ControllerBase and Controller is a direct inheritance, our Controller is the direct successor of the Controller.
{
if (requestContext == null)
{
throw new ArgumentNullException ("requestContext");
}
this.VerifyExecuteCalledOnce ();
this.Initialize (requestContext);
this.ExecuteCore ();
}
protected virtual void Initialize (RequestContext requestContext)
{
this.ControllerContext = new ControllerContext (requestContext, this);
}
protected abstract void ExecuteCore ();
Execute the main business on a ExecuteCore in, and this one ExecuteCore no code, just in the Controller has been overloaded business. (It seems ExecuteCore business or be placed under the Controller, while Initalize just RequestContext encapsulates ControllerContext, Microsoft is very interesting every step of repackaging a context).
look at the Controller ExecuteCore business
{
this.PossiblyLoadTempData ();
try
{
string requiredString = this.RouteData.GetRequiredString ("action");
if (! this.ActionInvoker.InvokeAction (base.ControllerContext, requiredString))
{
this.HandleUnknownAction (requiredString);
}
}
finally
{
this.PossiblySaveTempData ();
}
}
public IActionInvoker ActionInvoker
{
get
{
if (this._actionInvoker == null)
{
this._actionInvoker = this.CreateActionInvoker ();
}
return this._actionInvoker;
}
set
{
this._actionInvoker = value;
}
}
protected virtual IActionInvoker CreateActionInvoker ()
{
return new ControllerActionInvoker ();
}
ExectueCore call this.ActionInvoker.InvokeAction (base.ControllerContext, requiredString)) reflected executed Action. requiredString parameter is the name of Action
that before and after implementation of this Action is reflected there are other business do? Remember our. Net mvc see each Action method or Controller base class label is affixed to a number of attributes, Action performed before and what triggered it?
- Action Controller's OnActionExecuting first before executing the trigger
- Action execution is triggered after the Controller's OnActionExecuted
- Action affixed before and after implementation inheritance ActionFilterAttribute attribute tag OnActionExecuting, OnActionExecuted be executed (the Attribute as well as its privileges)
also said ControllerActionInvoker The InvokeAction method before executing the Action and Controller also had inherited attributes and Filter scans look InvokeAction specific content
{
if (controllerContext == null)
{
throw new ArgumentNullException ("controllerContext");
}
if (string.IsNullOrEmpty (actionName))
{
throw new ArgumentException (MvcResources.Common_NullOrEmpty, "actionName");
}
ControllerDescriptor controllerDescriptor = this.GetControllerDescriptor (controllerContext);
ActionDescriptor actionDescriptor = this.FindAction (controllerContext, controllerDescriptor, actionName);
if (actionDescriptor == null)
{
return false;
}
FilterInfo filters = this.GetFilters (controllerContext, actionDescriptor);
try
{
AuthorizationContext context = this.InvokeAuthorizationFilters (controllerContext, filters.AuthorizationFilters, actionDescriptor);
if (context.Result! = null)
{
this.InvokeActionResult (controllerContext, context.Result);
}
else
{
if (controllerContext.Controller.ValidateRequest)
{
ValidateRequest (controllerContext);
}
IDictionary
ActionExecutedContext context2 = this.InvokeActionMethodWithFilters (controllerContext, filters.ActionFilters, actionDescriptor, parameterValues);
this.InvokeActionResultWithFilters (controllerContext, filters.ResultFilters, context2.Result);
}
}
catch (ThreadAbortException)
{
throw;
}
catch (Exception exception)
{
ExceptionContext context3 = this.InvokeExceptionFilters (controllerContext, filters.ExceptionFilters, exception);
if (! context3.ExceptionHandled)
{
throw;
}
this.InvokeActionResult (controllerContext, context3.Result);
}
return true;
}
ControllerDescriptor controllerDescriptor = this.GetControllerDescriptor (controllerContext);
ActionDescriptor actionDescriptor = this.FindAction (controllerContext, controllerDescriptor, actionName);
The above two code is to read all of the Action Controller and descriptive information including tag attributes
FilterInfo filters = this.GetFilters (controllerContext, actionDescriptor); This code is read in front of all the specific reflective properties
ActionExecutedContext context2 = this.InvokeActionMethodWithFilters (controllerContext, filters.ActionFilters, actionDescriptor, parameterValues);
first run through InvokeActionMethodWithFilters Action Front intercept method, and then Action, followed by post-intercept method. Is not part of realization of AOP functionality? Of course, it did not do the AOP around intercept feature, but it is an improvement compared to a lot of WebForm.
fact, the above InvokeAction how to achieve specific intercept before I did not see it, I was through the implementation of the follow-up of two classes override breakpoints view.
five, rewritten Controller with ControllerActionInvoker
Here is rewriting the code
View Codeusing System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.IO;
namespace MvcApplication.Module
{
public class MyController: Controller
{
public MyController ()
{
/ / this.ActionInvoker = new MyControllerActionInvoker ();
}
protected override void OnActionExecuting (ActionExecutingContext filterContext)
{
base.OnActionExecuting (filterContext);
}
protected override void OnActionExecuted (ActionExecutedContext filterContext)
{
base.OnActionExecuted (filterContext);
}
/ / /
/ / / Action and front and rear with the intercept of the caller of the method
/ / /
/ / /
protected override IActionInvoker CreateActionInvoker ()
{
return new MyControllerActionInvoker ();
}
}
public class MyControllerActionInvoker: ControllerActionInvoker
{
public override bool InvokeAction (System.Web.Mvc.ControllerContext controllerContext, string actionName)
{
if (controllerContext == null)
{
throw new ArgumentNullException ("controllerContext");
}
if (string.IsNullOrEmpty (actionName))
{
/ / throw new ArgumentException (MvcResources.Common_NullOrEmpty, "actionName");
}
ControllerDescriptor controllerDescriptor = this.GetControllerDescriptor (controllerContext);
ActionDescriptor actionDescriptor = this.FindAction (controllerContext, controllerDescriptor, actionName);
if (actionDescriptor == null)
{
return false;
}
/ / note here
没有评论:
发表评论