ASP.NET Web API 过滤器创建、执行过程(一)

简介:

ASP.NET Web API 过滤器创建、执行过程()

前言

在上一篇中我们讲到控制器的执行过程系列,这个系列要搁置一段时间了,因为在控制器执行的过程中包含的信息都是要单独的用一个系列来描述的,就如今天的这个篇幅就是在上面内容之后所看到的一个知识要点之一。


ASP.NETWeb API 过滤器创建、执行过程()

下面就来讲解一下在ASP.NET Web API框架中过滤器的创建、执行过程。

过滤器所在的位置

1

wKiom1QHM6yAodThAAMGaQj_SgA431.jpg

1所示的就是控制器执行过程很粗略的表示。

通过上一篇内容我们了解到控制器方法选择器最后返回的并不是控制器方法,而是对于控制器方法描述的类型HttpActionDescriptorHttpActionDescriptor包含了控制器方法的一切信息,今天要讲的就是HttpActionDescriptor对象中生成的过滤器管道执行的这么一个顺序,当然其中就已经包含了创建的时候。

 

在介绍HttpActionDescriptor类型生成过滤器管道之前,我们先来对着其中会涉及到的一些类型进行一个基础的了解。

基础类型一览

FilterInfo 过滤器对象封装信息(System.Web.Http.Filters

示例代码1-1

1
2
3
4
5
6
7
    publicsealedclassFilterInfo
    {
         publicFilterInfo(IFilterinstance, FilterScopescope);
  
         publicIFilterInstance {  get ; }
         publicFilterScopeScope {  get ; }
    }


在代码1-1中想必大家也看到了,FilterInfo类型中有两属性,一个是有着过滤器类型的实例对象的引用也就是IFilter类型的Instance属性,还有一个是FilterScope类型的Scope属性表示当前这个过滤器在项目中的应用范围,这个值很重要,在过滤器管道中可是根据这个值来排序的。

 

FilterScope 过滤器应用范围(System.Web.Http.Filters

示例代码1-2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
    publicenumFilterScope
    {
         // 摘要:
         //     在 Controller 之前指定一个操作。
         Global=0,
         //
         // 摘要:
         //     在 Action 之前和 Global 之后指定一个顺序。
         Controller=10,
         //
         // 摘要:
         //     在 Controller 之后指定一个顺序。
         Action=20,
    }


从代码1-2中一目了然了,这里就不多说了。

 

IFilter 过滤器顶层接口(System.Web.Http.Filters

示例代码1-3

1
2
3
4
5
6
7
8
9
    publicinterfaceIFilter
    {
         // 摘要:
         //     获取或设置一个值,该值指示是否可以为单个程序元素指定多个已指示特性的实例。
         //
         // 返回结果:
         //     如果可以指定多个实例,则为 true;否则为 false。默认值为 false。
         boolAllowMultiple {  get ; }
    }


 

FilterAttribute过滤器默认实现特性类(System.Web.Http.Filters

示例代码1-4

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    // 摘要:
    //     表示操作-筛选器特性的基类。
    [AttributeUsage(AttributeTargets.Class|AttributeTargets.Method, Inherited= true , AllowMultiple= true )]
    publicabstractclassFilterAttribute : Attribute, IFilter
    {
         // 摘要:
         //     初始化 System.Web.Http.Filters.FilterAttribute 类的新实例。
         protectedFilterAttribute();
  
         // 摘要:
         //     获取用于指示是否允许多个筛选器的值。
         //
         // 返回结果:
         //     如果允许多个筛选器,则为 true;否则为 false。
         publicvirtualboolAllowMultiple {  get ; }
    }


示例代码1-4中我们可以看到FilterAttribute类型为过滤器默认的特性类型,而我们如果要想实现自定义的过滤器仅仅靠继承自FilterAttribute是不行的,因为FilterAttribute特性类只是属于过滤器概念中的“属性”,而过滤器中的行为则是由过滤器类型来控制器的,也就是下面要说的。

 

IActionFilter 行为过滤器接口(System.Web.Http.Filters

示例代码1-5

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
    publicinterfaceIActionFilter : IFilter
    {
         // 摘要:
         //     异步执行筛选器操作。
         //
         // 参数:
         //   actionContext:
         //     操作上下文。
         //
         //   cancellationToken:
         //     为此任务分配的取消标记。
         //
         //   continuation:
         //     在调用操作方法之后,委托函数将继续。
         //
         // 返回结果:
         //     为此操作新建的任务。
         Task<System.Net.Http.HttpResponseMessage>ExecuteActionFilterAsync(HttpActionContextactionContext, CancellationTokencancellationToken, Func<Task<System.Net.Http.HttpResponseMessage>>continuation);
     }


这里暂时不对行为过滤器接口类型做什么讲解,在最后的示例中会有运用到,而对于剩下的验证过滤器和异常过滤器接口也都差不多了,这里就单独的演示一个行为过滤器。

过滤器管道生成过程

这里我们还是要说到之前说过的HttpActionDescriptor类型,我来说一下大概的过程,首先呢在HttpActionDescriptor类型中有个内部字段叫_filterPipeline,从命名上就可以看出来大概的意思了,对的,过滤器管道的信息就是在这个字段中的,而它是个Lazy<Collection<FilterInfo>>类型。

 

ApiController的执行中有个私有类型是FilterGrouping类型,它这个类型的作用是对过滤器管道中的所有过滤器进行分类,就是验证归验证的,行为是行为的。

 

而实例化FilterGrouping类型的时候构造函数需要Collection<FilterInfo>类型的参数(也就是过滤器管道)来进行实例化,这个时候就是HttpActionDescriptor类型一展身手的时候了,看代码1-6就是HttpActionDescriptor类型重的函数。

 

示例代码1-6

1
2
3
4
    publicvirtualCollection<FilterInfo>GetFilterPipeline()
    {
         returnthis._filterPipeline.Value;
    }


在上面我们也说到了_filterPipeline这个字段,那么它的Value在这个时候做了什么呢?

代码1-6.1

1
    this ._filterPipeline= newLazy<Collection<FilterInfo>>(newFunc<Collection<FilterInfo>>( this .InitializeFilterPipeline));


看到这里我们只需要关注InitializeFilterPipeline这个函数的实现。

代码1-6.2

1
2
3
4
    privateCollection<FilterInfo>InitializeFilterPipeline()
    {
         returnnewCollection<FilterInfo>(RemoveDuplicates((fromfpinthis._configuration.Services.GetFilterProviders() selectfp.GetFilters( this ._configuration,  this )).OrderBy<FilterInfo, FilterInfo>(f=>f, FilterInfoComparer.Instance).Reverse<FilterInfo>()).Reverse<FilterInfo>().ToList<FilterInfo>());
    }


首先我们从这里看到的是,会从HttpConfiguration中的服务容器中获取基础服务,也就是实现了IFilterProvider的服务,而在其中也是有两个过滤器提供程序,下面我直接贴上源码

示例代码1-7

1
2
3
4
5
6
7
8
9
10
11
12
    publicclassConfigurationFilterProvider : IFilterProvider
    {
         //Methods
         publicIEnumerable<FilterInfo>GetFilters(HttpConfigurationconfiguration, HttpActionDescriptoractionDescriptor)
         {
             if  (configuration== null )
             {
                 throwError.ArgumentNull( "configuration" );
             }
             returnconfiguration.Filters;
         }
    }


在代码1-7中返回的就是HttpConfiguration中的Filters属性中的值。这里了解一下继续往下看,代码1-8

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    publicclassActionDescriptorFilterProvider : IFilterProvider
    {
         //Methods
         publicIEnumerable<FilterInfo>GetFilters(HttpConfigurationconfiguration, HttpActionDescriptoractionDescriptor)
         {
             if  (configuration== null )
             {
                 throwError.ArgumentNull( "configuration" );
             }
             if  (actionDescriptor== null )
             {
                 throwError.ArgumentNull( "actionDescriptor" );
             }
             IEnumerable<FilterInfo>first=frominstanceinactionDescriptor.ControllerDescriptor.GetFilters() selectnewFilterInfo(instance, FilterScope.Controller);
             IEnumerable<FilterInfo>second=frominstanceinactionDescriptor.GetFilters() selectnewFilterInfo(instance, FilterScope.Action);
             returnfirst.Concat<FilterInfo>(second);
         }
    }


在代码1-7中返回的是注册在全局范围使用的过滤器,而在代码1-8中则是控制器和控制器方法范围的过滤器。

这个时候我们再看代码1-6.2中的FilterInfoComparer.Instance的默认实现。

代码1-9

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    publicintCompare(FilterInfox, FilterInfoy)
    {
         if  ((x== null ) && (y== null ))
         {
             return0;
         }
         if  (x== null )
         {
             return -1;
         }
         if  (y== null )
         {
             return1;
         }
         return  ( int ) (x.Scope-y.Scope);
    }


 

过滤器管道生成结果示例

看到这里大家想必已经知道了返回的过滤器管道中是什么样子的了吧,如果不清楚也没关系,下面的示例来说明一下。

 

同种类型过滤器覆盖面的执行优先级:

服务端(SelfHost:

代码1-10

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
usingSystem.Web.Http.Controllers;
usingSystem.Web.Http.Filters;
usingNameSpaceControllerThree;
  
namespaceSelfHost
{
    classProgram
    {
         staticvoidMain( string [] args)
         {
  
            
  
             HttpSelfHostConfigurationselfHostConfiguration=
                 newHttpSelfHostConfiguration( "http://localhost/selfhost" );
             using  (HttpSelfHostServerselfHostServer=newHttpSelfHostServer(selfHostConfiguration))
             {
                 selfHostServer.Configuration.Routes.MapHttpRoute(
                     "DefaultApi" "api/{controller}/{id}" new  { id=RouteParameter.Optional });
                 selfHostServer.Configuration.Services.Replace( typeof (IAssembliesResolver),
                     newCustomAssembliesResolver.LoadSpecifiedAssembliesResolver());
                 //添加全局过滤器
                 selfHostServer.Configuration.Filters.Add(newWebAPIController.Filter.CustomConfigurationActionFilterAttribute());
                 selfHostServer.OpenAsync();
                 Console.WriteLine( "服务器端服务监听已开启" );
                 Console.Read();
             }
         }
    }
}


在服务端我们在HttpConfiguration中的Fileters属性中添加上了WebAPIController.Filter.CustomConfigurationActionFilterAttribute这个类型,下面会有说到。

WebAPIController项目中我会定义有控制器,以及同种过滤器的三种应用范围(用类型名称来区别了)。

首先我们看一下控制器类型的定义:

代码1-11

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
namespaceNameSpaceControllerThree
{
    [CustomControllerActionFilter]
    publicclassWriterAndReadController : ApiController
    {
         [CustomActionFilter]
         publicstringGet()
         {
             StringBuilderstrBuilder=newStringBuilder();
             HttpActionDescriptoractionDescriptor= this .Configuration.Services.GetActionSelector().SelectAction( this .ControllerContext);
             System.Collections.ObjectModel.Collection<FilterInfo>filtersInfo=actionDescriptor.GetFilterPipeline();
             foreach  (varfilterinfiltersInfo)
             {
                 strBuilder.AppendLine( "【FilterName:" +filter.Instance.GetType().Name+ ",FilterScope:" +filter.Scope.ToString()+ "】" );
             }
             returnstrBuilder.ToString();
         }
    }
}


可能看到这里对于下面自定义的行为过滤器会很感兴趣,那么就一起来看一下吧。

代码1-12

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
    publicclassCustomConfigurationActionFilterAttribute : FilterAttribute, IActionFilter
    {
  
         publicTask<System.Net.Http.HttpResponseMessage>ExecuteActionFilterAsync(System.Web.Http.Controllers.HttpActionContextactionContext, System.Threading.CancellationTokencancellationToken, Func<Task<System.Net.Http.HttpResponseMessage>>continuation)
         {
             //Console.WriteLine(this.GetType().Name);
             returncontinuation();
         }
    }
  
    publicclassCustomControllerActionFilterAttribute : FilterAttribute, IActionFilter
    {
  
         publicTask<System.Net.Http.HttpResponseMessage>ExecuteActionFilterAsync(System.Web.Http.Controllers.HttpActionContextactionContext, System.Threading.CancellationTokencancellationToken, Func<Task<System.Net.Http.HttpResponseMessage>>continuation)
         {
             //Console.WriteLine(this.GetType().Name);
             returncontinuation();
         }
    }
  
    publicclassCustomActionFilterAttribute : FilterAttribute, IActionFilter
    {
  
         publicTask<System.Net.Http.HttpResponseMessage>ExecuteActionFilterAsync(System.Web.Http.Controllers.HttpActionContextactionContext, System.Threading.CancellationTokencancellationToken, Func<Task<System.Net.Http.HttpResponseMessage>>continuation)
         {
             //Console.WriteLine(this.GetType().Name);
             returncontinuation();
         }
    }


我这里是定义的三个行为过滤器,在默认实现中为了方便直接是调用continuation委托来进行操作,便于外部的叠加器使用。

这个时候我们在运行起来服务端过后,不管是通过浏览器访问还是客户端访问都可以看到如下的结果图。

2

wKiom1QHNGeSt7MkAAMFaIyeAGQ131.jpg



     本文转自jinyuan0829 51CTO博客,原文链接:http://blog.51cto.com/jinyuan/1548571,如需转载请自行联系原作者






相关文章
|
29天前
|
JSON 编解码 API
Go语言网络编程:使用 net/http 构建 RESTful API
本章介绍如何使用 Go 语言的 `net/http` 标准库构建 RESTful API。内容涵盖 RESTful API 的基本概念及规范,包括 GET、POST、PUT 和 DELETE 方法的实现。通过定义用户数据结构和模拟数据库,逐步实现获取用户列表、创建用户、更新用户、删除用户的 HTTP 路由处理函数。同时提供辅助函数用于路径参数解析,并展示如何设置路由器启动服务。最后通过 curl 或 Postman 测试接口功能。章节总结了路由分发、JSON 编解码、方法区分、并发安全管理和路径参数解析等关键点,为更复杂需求推荐第三方框架如 Gin、Echo 和 Chi。
|
1月前
|
自然语言处理 算法 API
阿里云增值税发票识别NET Rest API调用示例
本文介绍了使用NET代码调用阿里云增值税发票识别API的实现方式。通过示例代码,详细展示了如何构造请求、设置签名以及发送HTTP请求的具体步骤。代码中涵盖了请求参数的处理、签名生成逻辑(如HMAC-SHA256算法)以及调用API后的结果处理。此外,还提供了运行结果的截图和参考文档链接,帮助开发者更好地理解和应用该接口。
110 4
|
3月前
|
人工智能 搜索推荐 IDE
突破网页数据集获取难题:Web Unlocker API 助力 AI 训练与微调数据集全方位解决方案
本文介绍了Web Unlocker API、Web-Scraper和SERP API三大工具,助力解决AI训练与微调数据集获取难题。Web Unlocker API通过智能代理和CAPTCHA绕过技术,高效解锁高防护网站数据;Web-Scraper支持动态内容加载,精准抓取复杂网页信息;SERP API专注搜索引擎结果页数据抓取,适用于SEO分析与市场研究。这些工具大幅降低数据获取成本,提供合规保障,特别适合中小企业使用。粉丝专属体验入口提供2刀额度,助您轻松上手!
145 2
|
9月前
|
Java API 数据库
构建RESTful API已经成为现代Web开发的标准做法之一。Spring Boot框架因其简洁的配置、快速的启动特性及丰富的功能集而备受开发者青睐。
【10月更文挑战第11天】本文介绍如何使用Spring Boot构建在线图书管理系统的RESTful API。通过创建Spring Boot项目,定义`Book`实体类、`BookRepository`接口和`BookService`服务类,最后实现`BookController`控制器来处理HTTP请求,展示了从基础环境搭建到API测试的完整过程。
137 4
|
9月前
|
XML JSON API
ServiceStack:不仅仅是一个高性能Web API和微服务框架,更是一站式解决方案——深入解析其多协议支持及简便开发流程,带您体验前所未有的.NET开发效率革命
【10月更文挑战第9天】ServiceStack 是一个高性能的 Web API 和微服务框架,支持 JSON、XML、CSV 等多种数据格式。它简化了 .NET 应用的开发流程,提供了直观的 RESTful 服务构建方式。ServiceStack 支持高并发请求和复杂业务逻辑,安装简单,通过 NuGet 包管理器即可快速集成。示例代码展示了如何创建一个返回当前日期的简单服务,包括定义请求和响应 DTO、实现服务逻辑、配置路由和宿主。ServiceStack 还支持 WebSocket、SignalR 等实时通信协议,具备自动验证、自动过滤器等丰富功能,适合快速搭建高性能、可扩展的服务端应用。
509 3
|
4月前
|
XML JSON API
Understanding RESTful API and Web Services: Key Differences and Use Cases
在现代软件开发中,RESTful API和Web服务均用于实现系统间通信,但各有特点。RESTful API遵循REST原则,主要使用HTTP/HTTPS协议,数据格式多为JSON或XML,适用于无状态通信;而Web服务包括SOAP和REST,常用于基于网络的API,采用标准化方法如WSDL或OpenAPI。理解两者区别有助于选择适合应用需求的解决方案,构建高效、可扩展的应用程序。
|
6月前
|
人工智能 前端开发 API
Gemini Coder:基于 Google Gemini API 的开源 Web 应用生成工具,支持实时编辑和预览
Gemini Coder 是一款基于 Google Gemini API 的 AI 应用生成工具,支持通过文本描述快速生成代码,并提供实时代码编辑和预览功能,简化开发流程。
327 38
Gemini Coder:基于 Google Gemini API 的开源 Web 应用生成工具,支持实时编辑和预览
|
4月前
|
机器学习/深度学习 开发框架 API
Python 高级编程与实战:深入理解 Web 开发与 API 设计
在前几篇文章中,我们探讨了 Python 的基础语法、面向对象编程、函数式编程、元编程、性能优化、调试技巧以及数据科学和机器学习。本文将深入探讨 Python 在 Web 开发和 API 设计中的应用,并通过实战项目帮助你掌握这些技术。
|
6月前
|
开发框架 数据可视化 .NET
.NET 中管理 Web API 文档的两种方式
.NET 中管理 Web API 文档的两种方式
99 14
|
7月前
|
Kubernetes 安全 Devops
有效抵御网络应用及API威胁,聊聊F5 BIG-IP Next Web应用防火墙
有效抵御网络应用及API威胁,聊聊F5 BIG-IP Next Web应用防火墙
208 10
有效抵御网络应用及API威胁,聊聊F5 BIG-IP Next Web应用防火墙

热门文章

最新文章