Objective
The previous article explained the creation of the filter before it was executed, registering it with the service container in the current httpconfiguration by implementing Ifilterprovider, and of course the default underlying service is also available, sorted by the collection of filter information obtained by these providers. This article explains a series of actions that the filter has done after it has been created.
ASP. NET Web API filter creation, execution process (ii)
filtergrouping
Filter Grouping Type
The filtergrouping type is a private type in the Apicontroller type, it acts as if it were named, and is used to group the filter set, as we saw in the previous article, After calling the Httpactiondescriptor type's Getfilterpipeline () method, go back to get the filter information collection collection<filterinfo> after sorting. Let's take a look at the filtergrouping type definition:
Example code 1-1
Private class Filtergrouping {//fields private list<iactionfilter> _actionfilters = new list& Lt;iactionfilter> (); Private list<iauthorizationfilter> _authorizationfilters = new list<iauthorizationfilter> (); Private list<iexceptionfilter> _exceptionfilters = new list<iexceptionfilter> (); Methods public filtergrouping (ienumerable<filterinfo> filters) {foreach (FilterInfo inf o in filters) {IFilter instance = info. Instance; Categorize<iactionfilter> (instance, this._actionfilters); Categorize<iauthorizationfilter> (instance, this._authorizationfilters); Categorize<iexceptionfilter> (instance, this._exceptionfilters); }} private static void Categorize<t> (IFilter filter, list<t> List) where T:class { T item = filter as T; if (item! = null) {list. ADD (item); }}//Properties public ienumerable<iactionfilter> actionfilters {get {return this._actionfilters; }} public ienumerable<iauthorizationfilter> Authorizationfilters {get { return this._authorizationfilters; }} public ienumerable<iexceptionfilter> Exceptionfilters {get { return this._exceptionfilters; } }}
In code 1-1 we see that the filter information set is grouped in the constructor of the filtergrouping type, of course, when grouping is called filtergrouping type, in categorize () The method is judged by the type of the instance, and finally by the three public attributes in the filtergrouping type to represent the different types of filter sets after grouping.
Filter Execution Process
In the last page we learned from the example of the filter pipeline generation process and the results, we look at the implementation of the process, incidentally, the result of the filter pipeline is not as described in the previous article.
First look at the server-side (selfhost) code:
Code 1-2
Using system.web.http.controllers;using system.web.http.filters;using namespacecontrollerthree;namespace SelfHost{ Class Program {static void Main (string[] args) {httpselfhostconfiguration Selfhos TConfiguration = new Httpselfhostconfiguration ("Http://localhost/selfhost"); using (httpselfhostserver selfhostserver = new Httpselfhostserver (selfhostconfiguration)) {Self HostServer.Configuration.Routes.MapHttpRoute ("Defaultapi", "Api/{controller}/{id}", new {id = Routepa Rameter. Optional}); SelfHostServer.Configuration.Services.Replace (typeof (Iassembliesresolver), new Customassembliesresolver . Loadspecifiedassembliesresolver ()); Add Global filter SELFHOSTSERVER.CONFIGURATION.FILTERS.ADD (new WebAPIController.Filter.CustomConfigurationActionFil Terattribute ()); Selfhostserver.openasync (); ConsolE.writeline ("Server-side service listener is turned on"); Console.read (); } } }}
There is only one line of code that adds a global behavior filter, and the rest is not explained.
Then we look at the Controller section, the following example code:
Code 1-3
namespace namespacecontrollerthree{ [Customcontrollerauthorizationfilter] [customcontrolleractionfilter ] public class Writerandreadcontroller:apicontroller { [customactionfilter] [ Customcontrolleractionauthorizationfilter] public string Get () { StringBuilder strbuilder = new StringBuilder (); Httpactiondescriptor Actiondescriptor = this. Configuration.Services.GetActionSelector (). SelectAction (this. ControllerContext); system.collections.objectmodel.collection<filterinfo> filtersinfo = Actiondescriptor.getfilterpipeline (); foreach (var filter in filtersinfo) { strbuilder.appendline ("" "FilterName:" +filter. Instance.gettype (). Name+ ", Filterscope:" +filter. Scope.tostring () + "" "); } return strbuilder.tostring ();}}}
For the previous article, the changes here are only in the controller type and controller methods have a new authorization filter, let's look at the definition of the filter, the following example code:
Code 1-4
<summary>//Global behavior Filter///</summary> public class Customconfigurationactionfilterattribute:fil Terattribute, Iactionfilter {public task<system.net.http.httpresponsemessage> executeactionfilterasync (Sy Stem. Web.Http.Controllers.HttpActionContext Actioncontext, System.Threading.CancellationToken CancellationToken, Func <Task<System.Net.Http.HttpResponseMessage>> continuation) {Console.WriteLine (this. GetType (). Name); return continuation (); }}///<summary>//Controller-level behavior Filter///</summary> public class Customcontrolleractionfilterattribu Te:filterattribute, Iactionfilter {public task<system.net.http.httpresponsemessage> ExecuteActionFilter Async (System.Web.Http.Controllers.HttpActionContext Actioncontext, System.Threading.CancellationToken CancellationToken, func<task<system.net.http.httpresponsemessage>> continuation) {Console.WRiteline (this. GetType (). Name); return continuation (); }}///<summary>//Controller method level behavior Filter///</summary> public class Customactionfilterattribute:fil Terattribute, Iactionfilter {public task<system.net.http.httpresponsemessage> executeactionfilterasync (Sy Stem. Web.Http.Controllers.HttpActionContext Actioncontext, System.Threading.CancellationToken CancellationToken, Func <Task<System.Net.Http.HttpResponseMessage>> continuation) {Console.WriteLine (this. GetType (). Name); return continuation (); }}///<summary>//Controller level authorization Access Filter///</summary> public class Customcontrollerauthorizationfilt Erattribute:filterattribute, Iauthorizationfilter {public task<system.net.http.httpresponsemessage> Exe Cuteauthorizationfilterasync (System.Web.Http.Controllers.HttpActionContext Actioncontext, System.Threading.CancellationToken CancellationToken, func<task<system.net.http.httpresponsemessage>> continuation) {Console.WriteLine (this. GetType (). Name); return continuation (); }}///<summary>//Controller method level authorization Access Filter///</summary> public class Customcontrolleractionauthoriza Tionfilterattribute:filterattribute, Iauthorizationfilter {public task<system.net.http.httpresponsemessage > Executeauthorizationfilterasync (System.Web.Http.Controllers.HttpActionContext actioncontext, System.Threading.CancellationToken CancellationToken, func<task<system.net.http.httpresponsemessage> > Continuation) {Console.WriteLine (this. GetType (). Name); return continuation (); }}
In code 1-4, we can see all the filter types used in code 1-3 and the addition of the global filter type in code 1-2.
Now let's look at the final results.
Figure 1
The result of the black box is the output of the Selfhost server-side filter execution process, in code 1-4 we can see that this concludes that the authorization filter regardless of the scope of the application is superior to the behavior filter, and in the same type of filter is based on the scope of application to determine the order of execution, This is related to the contents of the following browser, the browser shows that all the filters in the sorted pipeline, you can see the pipeline is purely in accordance with the level of application to sort, as to what the filter is in the process of sorting is not a bit of concern.
Filter Execution Process
-
Code Analysis
First look at the following, can represent the implementation of the controller during the process of the filter execution.
Figure 2
Above through the example to illustrate the implementation of the filter, now we look at the framework of the source code is what, because in the filter implementation process also contains other aspects of knowledge points, so this is to be seen sooner or later, let's look at it.
Code 1-5
Return Invokeactionwithexceptionfilters (Invokeactionwithauthorizationfilters (Actioncontext, CancellationToken, Authorizationfilters, () = ActionDescriptor.ActionBinding.ExecuteBindingAsync (Actioncontext, CancellationToken ). Then
There are three static methods involved in code 1-5, let's take a look at:
Invokeactionwithexceptionfilters ()
Invokeactionwithauthorizationfilters ()
Invokeactionwithactionfilters ()
The sample code is as follows:
Code 1-6
Internal static taskCode 1-7
Internal Static func<task
Code 1-8
Internal static func<task
Here we first look at the code 1-5 represents all the process of the filter execution, suddenly it seems that the 1-5 code readability is too low, may be with my level of relationship, I look very difficult and more irritable, but this rotten bone to chew, put in the past may be less learn a little things.
First we see the Invokeactionwithexceptionfilters () method called in code 1-5, which is code 1-6, so let's take a look at this invokeactionwithexceptionfilters () method, There are four parameters in the Invokeactionwithexceptionfilters () method, the first parameter is the task
Code 1-9
Invokeactionwithauthorizationfilters (Actioncontext, CancellationToken, authorizationfilters, () = ActionDescriptor.ActionBinding.ExecuteBindingAsync (Actioncontext, CancellationToken). Then
Find the part of code 1-9 is the parameters of the Invokeactionwithexceptionfilters () method, we see the name also know that the Invokeactionwithexceptionfilters () method executes the content of the exception filter, The first parameter type also said it was task
From code 1-9 you can see that the first call to code 1-7 is called the Invokeactionwithauthorizationfilters () method, we look at code 1-7.
The first method in code 1-7 has four parameters (Httpactioncontext actioncontext, CancellationToken CancellationToken, ienumerable< iauthorizationfilter> filters, func<taskfourth parameter is more important , this is a return task
Code 1-10
Invokeactionwithauthorizationfilters (Actioncontext, CancellationToken, Authorizationfilters,) ()
From the above, we know that the part of code 1-10 just returns an instance of the Task
Code 1-11
() = ActionDescriptor.ActionBinding.ExecuteBindingAsync (Actioncontext, CancellationToken). Then
In code 1-11, the main method is to call the Executebindingasync () method under the Actionbinding property of Actiondescriptor, where the model binding model validation is located. Some friends will find that the Executebindingasync () method returns the type of the Task, with the type of the required parameter described above as FUN<TASK<HTTPRESPONSEMESSAGE>> <task>, is not in accordance with, and according to logically also does not conform to AH, after the authorization filter executes should be the behavior filter execution, here involves a Task extension method call, is the Then<> () method.
Code 1-12
Internal static task<touterresult> then<touterresult> (this task task, func<task<touterresult> > Continuation, CancellationToken cancellationtoken = new CancellationToken (), bool runsynchronously = false) { Return task. Thenimpl<task, touterresult> (t = continuation (), CancellationToken, runsynchronously);}
A type with an extension method is a private struct type, and here it does not go down, it is here to convert the task to the task
Code 1-13
delegate { this._modelstate = actioncontext.modelstate; Return Invokeactionwithactionfilters (Actioncontext, CancellationToken, actionfilters, () = Controllerservices.getactioninvoker (). Invokeactionasync (Actioncontext, CancellationToken)) (); }
See here is a Actioncontext.modelstate property value that represents the result value of the model validation, and this this._modelstate is the current apicontroller,_ The Modelstate field corresponds to the Modelstate value in the Apicontroller type, after which the last 1-8 code is called, and in the above 1-13 we can see what the last object is to perform the final operation, which is explained later in this series of procedures.
After all of this is done, the code 1-6 is executed and the final code 1-5 is formed.
Jinyuan
Source: http://www.cnblogs.com/jin-yuan/
ASP. NET Web API filter creation, execution process (ii)