2013年7月31日星期三

Understanding. Net MVC implementation principle Controller / Action

 
  
   

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

   
    View Code     
     
            
     
      [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal), AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]       
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 k__BackingField;       
[CompilerGenerated]       
private string k__BackingField;       
      
/ / Properties       
public IHttpHandler HttpHandler       
{       
[CompilerGenerated]       
get       
{       
return this. k__BackingField;       
}       
[CompilerGenerated]       
set       
{       
this. k__BackingField = value;       
}       
}       
      
public string OriginalPath       
{       
[CompilerGenerated]       
get       
{       
return this. k__BackingField;       
}       
[CompilerGenerated]       
set       
{       
this. k__BackingField = value;       
}       
}       
}       
}       
      
     
     
            
    
   
   

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

   
    
          
    
     / / Properties      
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.

   
    View Code     
     
            
     
      public class MvcApplication: System.Web.HttpApplication       
{       
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.

   
    
          
    
     public static Route MapRoute (this RouteCollection routes, string name, string url, object defaults, object constraints, string [] namespaces)      
{      
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.

   
    View Code     
     
            
     
      public class MvcRouteHandler: IRouteHandler       
{       
/ / 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,

   
    
     RequestData data2 = new RequestData ();      
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 MvcHandler

decompile source code, you can see that in addition to inherit IHttpHandler, also inherited IRequireSeesionState. Custom HttpHandler want to deal Session words must inherit IRequireSeesionState.

   
    View Code     
     
            
     
      public class MvcHandler: IHttpAsyncHandler, IHttpHandler, IRequiresSessionState       
{       
/ / Fields       
private ControllerBuilder _controllerBuilder;       
private static readonly object _processRequestTag = new object ();       
[CompilerGenerated]       
private static bool k__BackingField;       
[CompilerGenerated]       
private RequestContext k__BackingField;       
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 > (delegate (KeyValuePair entry) {       
return (entry.Value == UrlParameter.Optional);       
}). Select , string> (delegate (KeyValuePair entry) {       
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 k__BackingField;       
}       
[CompilerGenerated]       
set       
{       
k__BackingField = value;       
}       
}       
      
protected virtual bool IsReusable       
{       
get       
{       
return false;       
}       
}       
      
public RequestContext RequestContext       
{       
[CompilerGenerated]       
get       
{       
return this. k__BackingField;       
}       
[CompilerGenerated]       
private set       
{       
this. k__BackingField = value;       
}       
}       
      
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

   
    
          
    
     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}));      
}      
}     
    
          
   
   

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

   
    View Code     
     
            
     
      using System;       
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 AccountController: 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.

   
    View Code     
     
            
     
      protected virtual void Execute (RequestContext requestContext)       
{       
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

   
    
          
    
     protected override void ExecuteCore ()      
{      
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

   
        
   
    View Code     
     
            
     
      public virtual bool InvokeAction (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;       
}       
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 parameterValues ​​= this.GetParameterValues ​​(controllerContext, actionDescriptor);       
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 Code     
     
            
     
      using System;       
using 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       
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 parameterValues ​​= this.GetParameterValues ​​(controllerContext, actionDescriptor);       
/ / This method execution, OnActionExecuting, OnActionExecuted, Action is triggered corresponding respectively       
ActionExecutedContext context2 = this.InvokeActionMethodWithFilters (controllerContext, filters.ActionFilters, actionDescriptor, parameterValues);       
this.InvokeActionResultWithFilters (controllerContext, filters.ResultFilters, context2.Result);       
}       
}       
catch (IOException ex)       
{       
throw;       
}       
catch (Exception exception)       
{       
ExceptionContext context3 = this.InvokeExceptionFilters (controllerContext, filters.ExceptionFilters, exception);       
if (! context3.ExceptionHandled)       
{       
throw;       
}       
this.InvokeActionResult (controllerContext, context3.Result);       
}       
return true;       
      
}       
}       
      
/ / /       
/ / / custom interceptor tag attributes for testing       
/ / /
      
public class MyActionFilterAttribute: ActionFilterAttribute       
{       
public override void OnActionExecuted (ActionExecutedContext filterContext)       
{       
base.OnActionExecuted (filterContext);       
}       
      
public override void OnActionExecuting (ActionExecutingContext filterContext)       
{       
base.OnActionExecuting (filterContext);       
}       
}       
}      
     
            
    
   
   

debug backward to MyControllerActionInvoker.InvokeAction structure observed filters

   

   

   

come to this position when the breakpoint

   

   

MyController and FilterAttribute attributes OnActionExecuting are executed first, followed by Action is executed, then the OnActionExecuted MyController and FilterAttribute also been carried out.

   

request from the client to the Controller of the specific Action implementation process is basically gone again on. net mvc mechanisms also have a certain understanding, I believe. net mvc development of much help, at least Based on the understanding that he can give full play the advantages and characteristics. The next section, we continue to learn through Refletor results returned ActionResult Action is how to return the bound value to the view and the view of the mechanism of the engine.

   

. net MVC3 added many new features, such as client remote authentication RemoteAttribute, such as the new Razor view engine.

   

added: Filter is read, to be performed in a certain order. We look at the InvokeAction ControllerActionInvoker method reads all tag attributes

   
    View Code     
     
            
     
      protected virtual FilterInfo GetFilters (ControllerContext controllerContext, ActionDescriptor actionDescriptor)       
{       
FilterInfo filters = actionDescriptor.GetFilters ();       
ControllerBase controller = controllerContext.Controller;       
AddControllerToFilterList (controller, filters.ActionFilters);       
AddControllerToFilterList (controller, filters.ResultFilters);       
AddControllerToFilterList (controller, filters.AuthorizationFilters);       
AddControllerToFilterList (controller, filters.ExceptionFilters);       
return filters;       
}      
     
            
    
   
   

were read IActionFilter, IAuthorizationFilter, IResultFilter, IExceptionFilter Properties tab, of course, including Controller itself.

   

then continue watching InvokeAction executing code:

   

executed first is IAuthorizationFilter

   

AuthorizationContext context = this.InvokeAuthorizationFilters (controllerContext, filters.AuthorizationFilters, actionDescriptor);

   

followed IActionFilter (Action also occurs in this position)

   

ActionExecutedContext context2 = this.InvokeActionMethodWithFilters (controllerContext, filters.ActionFilters, actionDescriptor

   

look carefully placed context2 found IResultFilter behind in the implementation of this method

   

this.InvokeActionResultWithFilters (controllerContext, filters.ResultFilters, context2.Result);

   

Finally IExceptionFilter

   

ExceptionContext context3 = this.InvokeExceptionFilters (controllerContext, filters.ExceptionFilters, exception);

   

Above is the Filter and Action execution order. This variable previously despised others A1, A2, A3 is that Microsoft also do so, and I'm not a good spade (-_-| | |).

   

left a question? The parameters passed to Action is how to convert the object? This I have yet to see how the code is implemented. Because MVC source code, you do not have to Refletor read, tomorrow to analyze the source code under the parameters passed to Action is how to transform into objects.

   

Source: http://www.cnblogs.com/ mecity/archive/2011/06/27/2090657.html

  
 

没有评论:

发表评论