ASP. NET Web API filter creation and execution process (1), asp. netapi

Source: Internet
Author: User

ASP. NET Web API filter creation and execution process (1), asp. netapi
ASP. NET Web API filter creation and execution process (1) Preface

In the previous article, we talked about the Controller execution process series. This series has to be put on hold for a while, because the information contained in the Controller execution process must be described in a series separately, today's article is one of the key points of knowledge that we will see after the above content.

ASP. NET Web API filter creation and execution process (1)

The following describes how to create and execute filters in the ASP. NET Web API framework.

Location of the filter

Figure 1

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

In the previous article, we learned that the final returned result of the Controller Method selector is not a controller method, but an HttpActionDescriptor of the type described by the Controller method. HttpActionDescriptor contains all information about the Controller method, today we will talk about the order in which the filter pipeline generated in the HttpActionDescriptor object is executed. Of course, this includes the creation time.

 

Before introducing the HttpActionDescriptor type to generate a filter pipeline, let's first make a basic understanding of some types involved in the pipeline.

Basic Types

FilterInfoFilter object encapsulation information (System. Web. Http. Filters)

Sample 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 attributes in the FilterInfo type. One is the reference of the Instance Object with the filter type, that is, the Instance attribute of the IFilter type, another is the Scope attribute of the FilterScope type, which indicates the application Scope of the current filter in the project. This value is very important and is sorted by this value in the filter pipeline.

 

FilterScopeFilter Application Scope (System. Web. Http. Filters)

Sample Code 1-2

Public enum FilterScope {// Abstract: // specify an operation before the Controller. Global = 0, // Summary: // specify an order before and after Action. Controller = 10, // Summary: // specify an order after the Controller. Action = 20 ,}

It is clear from code 1-2, so I won't say much here.

 

IFilterFilter top layer interface (System. Web. Http. Filters)

Sample Code 1-3

Public interface IFilter {// Summary: // gets or sets a value indicating whether multiple instances with indicated features can be specified for a single program element. //// Return result: // true if multiple instances can be specified; otherwise, false. The default value is false. Bool AllowMultiple {get ;}}

 

FilterAttributeFilter default implementation feature class (System. Web. Http. Filters)

// Abstract: // represents the base class of the action-filter feature. [AttributeUsage (AttributeTargets. class | AttributeTargets. method, Inherited = true, AllowMultiple = true)] public abstract class FilterAttribute: Attribute, IFilter {// abstract: // initialize System. web. http. filters. A new instance of the FilterAttribute class. Protected FilterAttribute (); // Abstract: // gets the value that indicates whether multiple filters are allowed. //// Return result: // true if multiple filters are allowed; otherwise, false. Public virtual bool AllowMultiple {get ;}}

In the example code 1-4, we can see that the FilterAttribute type is the default feature type of the filter. If we want to implement a custom filter, it is not feasible to inherit from the FilterAttribute, because the FilterAttribute attribute class only belongs to the "attribute" in the filter concept, and the behavior in the filter is controlled by the filter type, that is, what we will talk about below.

 

IActionFilterBehavior filter interface (System. Web. Http. Filters)

Sample Code 1-5

Public interface IActionFilter: IFilter {// Abstract: // perform the filter operation asynchronously. //// Parameter: // actionContext: // operation context. //// CancellationToken: // unmark the task. //// Continuation: // after the operation method is called, the delegate function will continue. //// Return result: // The task created for this operation. Task <System. Net. Http. HttpResponseMessage> ExecuteActionFilterAsync (HttpActionContext actionContext, CancellationToken cancellationToken, Func <Task <System. Net. Http. HttpResponseMessage> continuation );}

The following section does not explain the type of the behavior filter interface for the time being. It will be used in the final example, and the remaining authentication filters and exception filter interfaces are also similar, here we will separately demonstrate a behavior filter.

Filter pipeline Generation Process

Here we still need to talk about the HttpActionDescriptor type mentioned earlier. Let me take a look at the rough process. First of all, there is an internal field in the HttpActionDescriptor type named _ filterPipeline, we can see the approximate meaning from the name. Right, the information of the filter pipeline is in this field, and it is a Lazy <Collection <FilterInfo> type.

In the execution of ApiController, a private type is FilterGrouping. This type is used to classify all the filters in the filter pipeline, that is, verify that they are verified, and the behavior is behavior.

When instantiating the FilterGrouping type, the constructor needs to instantiate parameters of the Collection <FilterInfo> type (that is, the filter pipeline). This is the time for the HttpActionDescriptor type to show its skills, see Code 1-6 as a function of the HttpActionDescriptor type.

 

Sample Code 1-6

    public virtual Collection<FilterInfo> GetFilterPipeline()    {        return this._filterPipeline.Value;    }

We also mentioned the _ filterPipeline field above, so what is its Value at this time?

Codes 1-6.1

this._filterPipeline =  new Lazy<Collection<FilterInfo>>(new Func<Collection<FilterInfo>>(this.InitializeFilterPipeline));

Here we only need to pay attention to the implementation of the InitializeFilterPipeline function.

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

First, we can see that the basic service is obtained from the service container in HttpConfiguration, that is, the Service implementing IFilterProvider, and there are two filter providers in it, below I directly paste the source code

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

In code 1-7, the returned value is the value of the Filters attribute in HttpConfiguration. Let's take a look at it,

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 returned filter is registered in the global scope, while in code 1-8, the filter is in the range of controller and Controller method.

Now let's look at the default Implementation of FilterInfoComparer. Instance in code 1.

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 the filter pipeline generation result

We can see that you already know what the returned filter pipeline looks like. If you don't know it, it doesn't matter. The following example shows it.

 

Priority of the same type of filter coverage:

Server (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 selfHostConfiguration = new HttpSelfHostConfiguration (" http://localhost/selfhost "); Using (HttpSelfHostServer selfHostServer = new HttpSelfHostServer (selfHostConfiguration) {selfHostServer. configuration. routes. mapHttpRoute ("DefaultApi", "api/{controller}/{id}", new {id = RouteParameter. optional}); selfHostServer. configuration. services. replace (typeof (IAssembliesResolver), new CustomAssembliesResolver. loadSpecifiedAssembliesResolver (); // Add the global filter selfHostServer. configuration. filters. add (new WebAPIController. filter. customConfigurationActionFilterAttribute (); selfHostServer. openAsync (); Console. writeLine ("Server Service listener enabled"); Console. read ();}}}}

 

On the server side, we add the WebAPIController. Filter. CustomConfigurationActionFilterAttribute type to the Fileters attribute in HttpConfiguration. We will discuss it below.

In the WebAPIController project, I will define a controller and three application scopes of the same filter (different by type name ).

First, let's take a 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();        }    }}

You may be interested in the following custom behavior filters. Let's take a look.

Code 1-12

 

    public class CustomConfigurationActionFilterAttribute : FilterAttribute, IActionFilter    {        public Task<System.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<System.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> 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();        }    }

 

Here are the three defined behavior filters. In the default implementation, you can directly call the continuation delegate for operations to facilitate the use of external overlays.

At this time, after running the server, you can see the following results for both browser access and client access.

Figure 2

 

 

Author: Jin Yuan

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

The copyright of this article is shared by the author and the blog Park. You are welcome to reprint this article. However, you must keep this statement without the author's consent and go to the Article Page.


How does ASPNET implement regular execution of a piece of code?

Method 1: Call the thread execution method and implement an endless loop in the method. Set the Sleep time for each loop. Method 2: Use System. timers. timer class; Method 3: Use System. threading. timer; usingSystem. collections; usingSystem. threading; publicclassTest {publicstaticvoidMain () {Test obj = newTest (); Console. writeLine (Thread. currentThread. managedThreadId. toString (); // Method 1: Call the Thread execution method to implement an endless loop in the method. The Sleep time of each loop is set to thread Thread = newThread (newThreadStart (obj. method1); thread. start (); // Method 2: Use System. timers. timer class S Ystem. timers. timer t = newSystem. timers. timer (100); // instantiate the Timer class and set the time interval t. elapsed + = newSystem. timers. elapsedEventHandler (obj. method2); // execute event t at the time of arrival. autoReset = true; // set whether to execute once (false) or always execute (true) t. enabled = true; // whether to execute System. timers. timer. elapsed event while (true) {Console. writeLine ("test _" + Thread. currentThread. managedThreadId. toString (); Thread. sleep (100);} // method 3: Use System. threading. timer // description of the Timer constructor parameters: // Callb Ack: A TimerCallback delegate, indicating the method to be executed. // State: an object that contains the information to be used by the callback method, or a null reference (Nothing in Visual Basic ). // DueTime: the time delay before calling callback (in milliseconds ). Specify Timeout. Infinite to prevent the timer from starting timing. Specify zero (0) to start the timer immediately. System. threading. timer threadTimer = newSystem. threading. timer (newSystem. threading. timerCallback (obj. method3), null, 0,100); while (true) {Console. writeLine ("test _" + Thread. currentThread. managedThreadId. toString (); Thread. sleep (100);} Console. readLine ();} voidMethod1 () {while (true) {Console. writeLine (DateTime. now. toString () + "_" + Thread. currentThread. managedThreadId. toString (); Thread. currentThread. join (100 )...... remaining full text>

How to include another web page in the aspnet web page

Use a custom control to write the content to be included into a custom control,
Then, call the custom control on the home page.
Example:
Create a custom control c_topwin.ascx
The content is the same as writing An aspx file.
Add the following at the top of the page to be called:
<% @ Register TagPrefix = "topwin" TagName = "c_topwin" Src = "/control/c_topwin.ascx" %>

TagPrefix: Control prefix
TagName: Control name
Src: control path

Finally, add the following to the place where you want to add the control:
<Topwin: c_topwin runat = "server" id = "c_topwin1"/>

Or

<Topwin: c_topwin runat = "server" id = "c_topwin1"> </topwin>

You can also dynamically load custom controls in the program.
You can use PlaceHolder to place a PlaceHolder first, and then use PlaceHolder1.Controls. Add (Page. LoadControl ("/control/c_topwin.ascx "));

However, the content of the dynamically loaded custom control disappears after the PostBack operation. The solution is as follows:
Add the PlaceHolder name ctl_main to the Page_Load method of the page:
If (! IsPostBack)
{
Control ctl = Page. LoadControl ("/control/c_topwin.ascx ");
Ctl. ID = "ctl_loaded ";
This. ctl_main.Controls.Add (ctl );
ViewState ["ctl_loaded"] = "/control/c_topwin.ascx ";
}
Else
{
Ctl = Page. LoadControl (ViewState ["ctl_loaded"]. ToString ());
Ctl. ID = "ctl_loaded ";
This. ctl_main.Controls.Add (ctl );
}
Add a flag in the view status to indicate whether the user control is loaded by clicking the button. Of course, if the user control has been loaded and then clicked, the user control does not need to be loaded again.

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.