Asp.net mvc journey-application and source code analysis of ActionFilter on the sixth station, mvcactionfilter
In this article, let's take a look at ActionFilter. From the perspective of its name, we probably know that ActionFilter is the Filter on Action, right? What are the filters on Action ???
This problem is actually quite simple, because we have heard that Mvc itself is a highly scalable framework. Naturally, it is intercepted and filtered at different layers, right, for example, we can see the following Controller class.
public abstract class Controller : ControllerBase, IActionFilter, IAuthenticationFilter, IAuthorizationFilter, IDisposable, IExceptionFilter, IResultFilter, IAsyncController, IController, IAsyncManagerContainer { }
From the Controller of this parent class, we can see five filters, such as IActionFilter, IAuthenticationFilter, IAuthorizationFilter, IExceptionFilter, IResultFilter,
Right, let's start with the first ActionFilter.
I. IActionFilter Parsing
Now we know that IActionFilter is an interface, and next we are interested in what is in this ActionFilter, such as below.
/// Abstract: // Defines the methods that are used in an action filter. public interface IActionFilter {// Abstract: // Called after the action method executes. //// parameter: // filterContext: // The filter context. void OnActionExecuted (ActionExecutedContext filterContext); // Abstract: // Called before an action method executes. //// parameter: // filterContext: // The filter context. void OnActionExecuting (ActionExecutingContext filterContext );}
From the code above, we can see that there are only two methods in this interface, one is OnActionExecuting and the other is OnActionExecuted. you should understand this name.
In fact, it is executed separately before and after the Action, right? In this case, you are smart enough to think of the Application Scenario, record the log, and obtain the access volume of the action, so as to facilitate subsequent charges ~~~ Next I
Let's see how to implement these two methods.
1. Implement ActionFilter using override
Now we all know that the Controller class has implemented this interface, so our XXXController just inherits this parent Controller, so in the face of this situation, we can use
Override.
1 public class HomeController : Controller 2 { 3 public ActionResult Index() 4 { 5 return View(); 6 } 7 8 protected override void OnActionExecuting(ActionExecutingContext filterContext) 9 {10 filterContext.HttpContext.Response.Write("hello");11 12 base.OnActionExecuting(filterContext);13 }14 15 protected override void OnActionExecuted(ActionExecutedContext filterContext)16 {17 filterContext.HttpContext.Response.Write("world");18 19 base.OnActionExecuted(filterContext);20 }21 }
In this way, we can implement it easily and happily. Isn't it very simple? But after careful consideration, there are still some restrictions on this method, that is, our override dependency is too strong, for example, only
Class extends IActionFilter is available. Next, let's see if there are more flexible methods to implement it.
2. Custom class extends IActionFilter
To achieve high flexibility, we must make this implementation class an "atomic unit" with this atomic unit, we can easily apply this undetachable atomicity to various places.
Right, right. This atom can be implemented using Attribute in C #, for example, the following:
1 public class MyActionFilterAttribute : Attribute, IActionFilter 2 { 3 public void OnActionExecuted(ActionExecutedContext filterContext) 4 { 5 filterContext.HttpContext.Response.Write("hello"); 6 } 7 8 public void OnActionExecuting(ActionExecutingContext filterContext) 9 {10 filterContext.HttpContext.Response.Write("world");11 }12 }
OK. Now we have obtained an atomic MyActionFilterAttribute feature. Next we can apply this MyActionFilterAttribute to any place, for example:
1 public class HomeController : Controller2 {3 [MyActionFilter]4 public ActionResult Index()5 {6 return View();7 }8 }
3. ActionFilterAttribute
In addition to implementing the following attributes and IActionFilter interfaces, We can inherit the ActionFilterAttribute feature provided by the mvc framework ~
1 // 2 // Summary: 3 // Represents the base class for filter attributes. 4 [AttributeUsage (AttributeTargets. class | AttributeTargets. method, Inherited = true, AllowMultiple = false)] 5 public abstract class ActionFilterAttribute: FilterAttribute, IActionFilter, IResultFilter 6 {7 // 8 // abstract: 9 // Initializes a new instance of the System. web. mvc. actionFilterAttribute class.10 protected ActionFilterAttribute (); 11 12 // 13 // Summary: 14 // Called by the ASP. net mvc framework after the action method executes.15 // 16 // parameter: 17 // filterContext: 18 // The filter context.19 public virtual void OnActionExecuted (ActionExecutedContext filterContext ); 20 // 21 // Summary: 22 // Called by the ASP. net mvc framework before the action method executes.23 // 24 // parameter: 25 // filterContext: 26 // The filter context.27 public virtual void OnActionExecuting (ActionExecutingContext filterContext ); 28 // 29 // Summary: 30 // Called by the ASP. net mvc framework after the action result executes.31 // 32 // parameter: 33 // filterContext: 34 // The filter context.35 public virtual void OnResultExecuted (ResultExecutedContext filterContext ); 36 // 37 // Summary: 38 // Called by the ASP. net mvc framework before the action result executes.39 // 40 // parameter: 41 // filterContext: 42 // The filter context.43 public virtual void OnResultExecuting (ResultExecutingContext filterContext); 44}
From this Attribute, we can see that it integrates the IActionFilter and IResultFilter, and naturally there are methods for these two interfaces. Well, let's just say, Let's implement this abstract class.
namespace WebApplication2.Controllers{ public class HomeController : Controller { [MyActionFilter] public ActionResult Index() { return View(); } } public class MyActionFilterAttribute : ActionFilterAttribute { public override void OnActionExecuting(ActionExecutingContext filterContext) { base.OnActionExecuting(filterContext); } public override void OnActionExecuted(ActionExecutedContext filterContext) { base.OnActionExecuted(filterContext); } }}
Ii. Source Code Analysis
The best source code analysis method is to download a reflector plug-in, so that we can get the debugging code at runtime and the call stack we can see, especially the "Call Heap"
Stack "is very important to you.
1. First, we place the next breakpoint in the OnActionExecuting method, for example:
2. Roll back to the previous stack by calling the stack,
This method is actually very interesting. It can be seen from the method name that it is actually a recursive mode, that is, "OnActionExecuting" => "into the stack to execute BeginInvokeActionMethod"
=> The "OnActionExecuted" Method for Stack rollback has a nice statement, for example:
Func<ActionExecutedContext> continuation = this.InvokeActionMethodFilterAsynchronouslyRecursive(num);
Well, more details are waiting for you to study. I hope this article will help you ~~~