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

Source: Internet
Author: User

ASP. NET Web API filter creation and execution process (1)
Before introducing the HttpActionDescriptor type to generate a filter pipeline, let's first make a basic understanding of some types involved in the pipeline. Overview of basic types FilterInfo filter object encapsulation information (System. web. http. filters) sample code 1-1 copy the code public sealed class FilterInfo {public FilterInfo (IFilter instance, FilterScope scope); public IFilter Instance {get;} public FilterScope Scope {get ;}} the copy code can be seen 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. FilterScope filter application scope (System. Web. Http. Filters) sample code 1-2 copy the code 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,} copy the code at a glance from code 1-2. I won't say much here. IFilter filter top-level interface (System. web. http. filters) sample code 1-3 copy the code public interface IFilter {// Summary: // get or set a value, this value indicates 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 ;}} copy the code FilterAttribute filter to implement the default feature class (System. web. http. filters) copy the code // Summary: // 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;} copy the sample code 1-4. We can see that the FilterAttribute type is the default feature type of the filter, however, if we want to implement a custom filter, it is impossible to inherit from the FilterAttribute only because the FilterAttribute attribute class only belongs to the "attribute" in the filter concept ", the action in the filter is controlled by the filter type, that is, the following. IActionFilter (System. Web. Http. Filters) sample code 1-5 copy the code public interface IActionFilter: IFilter {// Summary: // asynchronous execution of the filter operation. //// 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);} copying the Code does not explain the behavior filter interface type at the moment. It will be used in the final example, the remaining authentication filters and exception filter interfaces are similar. Here we will separately demonstrate a behavior filter. In the process of generating the filter pipeline, we still need to talk about the HttpActionDescriptor type mentioned earlier. Let me talk about the general process. First of all, there is an internal field named _ filterPipeline in the HttpActionDescriptor type, 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 does the Value do at this time? Code 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. 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> ();} first, we can see that The service container obtains the basic service, that is, the IFilterProvider service, and there are two filter providers in it, below I directly paste the source code example code 1-7 copy the code public class ConfigurationFilterProvider: IFilterProvider {// Methods public IEnumerable <FilterInfo> GetFilters (HttpConfiguration configuration, HttpActionDescriptor actionDescriptor) {if (configuration = null) {throw Error. argumentNull ("configuration");} return configuration. filters;} copy the code. HttpConfigu is returned in code 1-7. The value in the Filters attribute in ration. Next, let's take a look at code 1-8. Copy the code 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 system returns a filter registered globally. In code 1-8, the filter is used within the range of the controller and Controller method. Now let's look at the default Implementation of FilterInfoComparer. Instance in code 1. Code 1-9 copy the code 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);} copy the code filter pipeline to generate the result example. You must have known what the returned filter pipeline looks like. It doesn't matter if it's unclear, the following is an example. Execution priority of the coverage of the same type of filter: Server (SelfHost): code 1-10 copy the code 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. configuratio N. filters. add (new WebAPIController. filter. customConfigurationActionFilterAttribute (); selfHostServer. openAsync (); Console. writeLine ("Server Service listener enabled"); Console. read () ;}}} copy the code to add WebAPIController to the Fileters attribute in HttpConfiguration on the server side. filter. the CustomConfigurationActionFilterAttribute type is described 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 copy the code 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. co Llection <FilterInfo> filtersInfo = actionDescriptor. getFilterPipeline (); foreach (var filter in filtersInfo) {strBuilder. appendLine ("[FilterName:" + filter. instance. getType (). name + ", FilterScope:" + filter. scope. toString () + "]");} return strBuilder. toString () ;}} the copied code may be very interested in the following custom behavior filter. Let's take a look at it. Code 1-12 copy the code 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); retu Rn 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 (). nam E); 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 () ;}} copy the code. Here are the three defined behavior filters. In the default implementation, to facilitate the operation, you can directly call the continuation delegate, it is easy for external overlay devices to use.

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.