ASP. NET Web API filter creation, execution process (i)

Source: Internet
Author: User

Objective

In the previous article we talked about the controller's execution process series, which was shelved for some time, because the information contained in the controller's execution was to be described in a single series, as is the case today is one of the points of knowledge that was seen after the above content.

ASP. NET Web API filter creation, execution process (i)

Here's a look at the creation and execution of filters in the ASP. NET WEB API framework.

Where the filter is located

Figure 1

Figure 1 shows a very rough representation of the controller execution process.

In the previous article, we learned that the Controller method selector returned is not the Controller method, but for the controller method description of the type Httpactiondescriptor,httpactiondescriptor contains all the information of the Controller method, What we're going to talk about today is the order in which the filter pipelines that are generated in the Httpactiondescriptor object are executed, which of course contains the time it was created.

Before we introduce the Httpactiondescriptor type Generation filter pipeline, let's start with a basic understanding of some of the types involved.

List of basic types

FilterInfo Filter Object Encapsulation Information ( System.Web.Http.Filters )

Example code 1-1

    public sealed class FilterInfo    {public        filterinfo (IFilter instance, filterscope scope);        Public IFilter Instance {get;}        Public Filterscope Scope {get;}    }

As you can see in code 1-1, there are two properties in the FilterInfo type, one is the reference to the instance object with the filter type, which is the instance attribute of the IFilter type. There is also a scope property of type Filterscope that indicates the current scope of the filter's application in the project, which is important, but is sorted by this value in the filter pipeline.

Filterscope Filter Application Range ( System.Web.Http.Filters )

Example code 1-2

    Public enum Filterscope    {        //digest:        //     Specify an action before the Controller.        global = 0,        ////        Summary:        //     Specify a sequence before Action and after global.        controller = ten,        /////        Abstract:        //     Specify a sequence after the controller.        Action = 20,   

At a glance from code 1-2, there's not much to say.

IFilter filter Top-level interface ( System.Web.Http.Filters )

Example code 1-3

    Public interface IFilter    {        ///Summary:        //     Gets or sets a value that indicates whether multiple instances of the indicated attribute can be specified for a single program element. ////        Returns the result:        //     True if multiple instances can be specified; otherwise false. The default value is False.        bool AllowMultiple {get;}    }

FilterAttribute Filter Default implementation attribute Class ( System.Web.Http.Filters )

    Summary:    //     represents the base class for the action-filter attribute.    [AttributeUsage (AttributeTargets.Class | AttributeTargets.Method, inherited = True, AllowMultiple = True)] public    abstract class Filterattribute:attribute, I Filter    {        //Summary:        //     Initializes a new instance of the System.Web.Http.Filters.FilterAttribute class.        protected FilterAttribute ();        Summary:        //     Gets a value that indicates whether multiple filters are allowed. ////        Returns the result:        //     True if multiple filters are allowed; otherwise false. Public        virtual bool AllowMultiple {get;}    }

In example code 1-4 we can see that the FilterAttribute type is the default attribute type of the filter, and we do not want to implement a custom filter simply by inheriting from FilterAttribute. Because the FilterAttribute attribute class simply belongs to the "attribute" in the filter concept, the behavior in the filter is controlled by the filter type, which is what is said below.

Iactionfilter Behavior Filter Interface ( System.Web.Http.Filters )

Example code 1-5

    Public interface Iactionfilter:ifilter    {        //digest:        //     asynchronously executes a filter action. ////        Parameters:        //   Actioncontext://     operation context. ////        CancellationToken://     Cancellation token assigned for this task. ////   Continuation:        //     After invoking the action method, the delegate function will continue. ////        return Result:        //     New task for this operation.        task<system.net.http.httpresponsemessage> Executeactionfilterasync (Httpactioncontext actionContext, CancellationToken CancellationToken, func<task<system.net.http.httpresponsemessage>> continuation);    }

For the time being, there is no explanation for the Behavior filter interface type, which is used in the last example, and for the rest of the validation filters and exception filter interfaces, where a single behavior filter is shown.

Filter Pipeline generation Process

Here we still have to talk about the Httpactiondescriptor type, I would like to say about the process, first of all, in the Httpactiondescriptor type has an internal field called _filterpipeline, From the name can be seen in the general meaning, right, the filter pipeline information is in this field, and it is a lazy<collection<filterinfo>> type.

In the execution of Apicontroller, there is a private type that is the filtergrouping type, which is the function of classifying all filters in the filter pipeline, that is, verifying the validation, and the behavior is behavior.

When instantiating a filtergrouping type, the constructor requires collection<filterinfo> type parameters (that is, the filter pipeline) to instantiate, This is the time to httpactiondescriptor type, see Code 1-6 is the function of httpactiondescriptor type weight.

Example code 1-6

    Public virtual collection<filterinfo> getfilterpipeline ()    {        return this._filterpipeline.value;    }

In the above we also talked about the _filterpipeline field, so what does its value do at this time?

Code 1-6.1

This._filterpipeline =  New lazy<collection<filterinfo>> (New func<collection<filterinfo> > (this. Initializefilterpipeline));

See here we only need to focus on the implementation of the Initializefilterpipeline function.

Code 1-6.2

    Private collection<filterinfo> Initializefilterpipeline ()    {        return new collection<filterinfo> ( RemoveDuplicates (from FP in This._configuration. Services.getfilterproviders () Select FP. Getfilters (This._configuration, this)). Orderby<filterinfo, filterinfo> (f = f, filterinfocomparer.instance). Reverse<filterinfo> ()). Reverse<filterinfo> (). Tolist<filterinfo> ());   }

The first thing we see from here is that we will get the basic service from the service container in Httpconfiguration, that is to realize the Ifilterprovider service, and there are two filter providers in it, below I paste the source code directly

Example code 1-7

    public class Configurationfilterprovider:ifilterprovider    {        //Methods public        Ienumerable<filterinfo > getfilters (httpconfiguration Configuration, Httpactiondescriptor actiondescriptor)        {            if (configuration = = null)            {                throw error.argumentnull ("configuration");            }            return configuration. Filters;        }    }

The value in the filters property in Httpconfiguration is returned in code 1-7. Here's a look, keep looking down,

Code 1-8

    public class Actiondescriptorfilterprovider:ifilterprovider    {        //Methods public        ienumerable< Filterinfo> getfilters (httpconfiguration configuration, Httpactiondescriptor actiondescriptor)        {            if ( Configuration = = null)            {                throw error.argumentnull ("configuration");            }            if (Actiondescriptor = = null)            {                throw error.argumentnull ("Actiondescriptor");            }            Ienumerable<filterinfo> first = from instance in ActionDescriptor.ControllerDescriptor.GetFilters () select New FilterInfo (instance, filterscope.controller);            ienumerable<filterinfo> second = from instance in Actiondescriptor.getfilters () select New FilterInfo (instance, filterscope.action);            return first. Concat<filterinfo> (second);        }   }

In code 1-7, the filters that are registered for use at the global scope are returned, and in code 1-8 are the filters for the controller and controller method scopes.

This time we look at the default implementation of Filterinfocomparer.instance in code 1-6.2.

Code 1-9

    public int Compare (FilterInfo x, filterinfo y)    {        if ((x = = null) && (y = = null))        {            return 0;        }        if (x = = null)        {            return-1;        }        if (y = = null)        {            return 1;        }        return (int) (x.scope-y.scope);   }

Example of filter pipeline generation results

See here you must already know what the filter in the return pipeline looks like, if not clear also does not matter, the following example to illustrate.

Execution priority for the same type of filter coverage:

Service side (Selfhost):

Code 1-10

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

On the server side we add the WebAPIController.Filter.CustomConfigurationActionFilterAttribute type to the Fileters attribute in Httpconfiguration, which will be said below.

In the Webapicontroller project I will define the controller and the three application ranges of the same filter (which are distinguished by the type name).

First we look at the definition of the controller type:

Code 1-11

namespace namespacecontrollerthree{    [Customcontrolleractionfilter] public    class Writerandreadcontroller: Apicontroller    {        [customactionfilter] 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 ();}}}    

It might be interesting to see the following custom behavior filters, so let's take a look.

Code 1-12

    public class Customconfigurationactionfilterattribute:filterattribute, Iactionfilter {public task<syst Em. Net.http.httpresponsemessage> Executeactionfilterasync (System.Web.Http.Controllers.HttpActionContext Actioncontext, System.Threading.CancellationToken CancellationToken, func<task< system.net.http.httpresponsemessage>> continuation) {//console.writeline (this. GetType ().            Name);        return continuation (); }} public class Customcontrolleractionfilterattribute:filterattribute, Iactionfilter {public task<s Ystem. Net.http.httpresponsemessage> Executeactionfilterasync (System.Web.Http.Controllers.HttpActionContext Actioncontext, System.Threading.CancellationToken CancellationToken, func<task< system.net.http.httpresponsemessage>> continuation) {//console.writeline (this. GetType ().            Name);        return continuation (); }} public class CustomactionfilterattribUte:filterattribute, Iactionfilter {public task<system.net.http.httpresponsemessage> ExecuteActionFilte Rasync (System.Web.Http.Controllers.HttpActionContext Actioncontext, System.Threading.CancellationToken CancellationToken, func<task<system.net.http.httpresponsemessage>> continuation) {//Console . WriteLine (this. GetType ().            Name);        return continuation (); }    }

I am here to define the three behavior filter, in the default implementation in order to facilitate the direct invocation of the continuation delegate to operate, convenient for external use of the adder.

This time we are running up the server after the end, whether through the browser access or client access can see the following result diagram.

Figure 2

Jinyuan

Source: http://www.cnblogs.com/jin-yuan/

ASP. NET Web API filter creation, execution process (i)

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.