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

简介:

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

前言

前面一篇中讲解了过滤器执行之前的创建,通过实现IFilterProvider注册到当前的HttpConfiguration里的服务容器中,当然默认的基础服务也是有的,并且根据这些提供程序所获得的的过滤器信息集合进行排序。本篇就会对过滤器在创建完之后所做的一系列操作进行讲解。

 

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

FilterGrouping过滤器分组类型

FilterGrouping类型是ApiController类型中的私有类型,它的作用就如同它的命名一样,用来对过滤器集合进行分组,在上一篇中我们看到,在经过调用HttpActionDescriptor类型的GetFilterPipeline()方法之后回去获取到排序过后的过滤器信息集合Collection<FilterInfo>。下面我们看一下FilterGrouping类型定义:

示例代码1-1

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
    privateclassFilterGrouping
    {
         //Fields
         privateList<IActionFilter>_actionFilters=newList<IActionFilter>();
         privateList<IAuthorizationFilter>_authorizationFilters=newList<IAuthorizationFilter>();
         privateList<IExceptionFilter>_exceptionFilters=newList<IExceptionFilter>();
  
         //Methods
         publicFilterGrouping(IEnumerable<FilterInfo>filters)
         {
             foreach  (FilterInfoinfoinfilters)
             {
                 IFilterinstance=info.Instance;
                 Categorize<IActionFilter>(instance,  this ._actionFilters);
                 Categorize<IAuthorizationFilter>(instance,  this ._authorizationFilters);
                 Categorize<IExceptionFilter>(instance,  this ._exceptionFilters);
             }
         }
  
         privatestaticvoidCategorize<T>(IFilterfilter, List<T>list)  where  T :  class
         {
             T item=filteras T;
             if  (item!= null )
             {
                 list.Add(item);
             }
         }
  
         //Properties
         publicIEnumerable<IActionFilter>ActionFilters
         {
             get
             {
                 returnthis._actionFilters;
             }
         }
  
         publicIEnumerable<IAuthorizationFilter>AuthorizationFilters
         {
             get
             {
                 returnthis._authorizationFilters;
             }
         }
  
         publicIEnumerable<IExceptionFilter>ExceptionFilters
         {
             get
             {
                 returnthis._exceptionFilters;
             }
         }
}


在代码1-1中我们看到在FilterGrouping类型的构造函数中便会对过滤器信息集合进行分组了,当然了分组的时候是调用FilterGrouping类型中的放吧,在Categorize()方法中就是根据实例的类型来进行判断的,最后由FilterGrouping类型中的三个公共属性来表示分组过后的不同类型的过滤器集合。

 

过滤器执行过程

在上个篇幅中我们通过示例了解到过滤器管道的生成过程以及结果,我们就来看一下执行的过程,顺带再看下过滤器管道的结果是不是如上篇上所说的那样。

先看服务器端(Selfhost)的代码:

代码1-2

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


这里只有一个添加全局行为过滤器的这么一句代码,其余的部分就不解释了。

然后我们接着看控制器部分,如下示例代码:

代码1-3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
namespaceNameSpaceControllerThree
{
    [CustomControllerAuthorizationFilter]
    [CustomControllerActionFilter]
    publicclassWriterAndReadController : ApiController
    {
         [CustomActionFilter]
         [CustomControllerActionAuthorizationFilter]
         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-4

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
/// <summary>
    /// 全局的行为过滤器
    /// </summary>
    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();
         }
    }
  
    /// <summary>
    /// 控制器级行为过滤器
    /// </summary>
    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();
         }
    }
  
    /// <summary>
    /// 控制器方法级行为过滤器
    /// </summary>
    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();
         }
    }
  
    /// <summary>
    /// 控制器级授权访问过滤器
    /// </summary>
    publicclassCustomControllerAuthorizationFilterAttribute : FilterAttribute, IAuthorizationFilter
    {
  
         publicTask<System.Net.Http.HttpResponseMessage>ExecuteAuthorizationFilterAsync(System.Web.Http.Controllers.HttpActionContextactionContext, System.Threading.CancellationTokencancellationToken, Func<Task<System.Net.Http.HttpResponseMessage>>continuation)
         {
             Console.WriteLine( this .GetType().Name);
             returncontinuation();
         }
    }
  
    /// <summary>
    /// 控制器方法级授权访问过滤器
    /// </summary>
    publicclassCustomControllerActionAuthorizationFilterAttribute : FilterAttribute, IAuthorizationFilter
    {
  
         publicTask<System.Net.Http.HttpResponseMessage>ExecuteAuthorizationFilterAsync(System.Web.Http.Controllers.HttpActionContextactionContext, System.Threading.CancellationTokencancellationToken, Func<Task<System.Net.Http.HttpResponseMessage>>continuation)
         {
             Console.WriteLine( this .GetType().Name);
             returncontinuation();
         }
}


在代码1-4中,我们可以看到代码1-3中所有使用到的过滤器类型和代码1-2中添加全局过滤器类型。

现在我们看一下最后的结果

1

wKioL1QVgHvwFFXaAANvgLXZvmM195.jpg

 

黑色框的结果为SelfHost服务器端过滤器执行过程的输出,在代码1-4中我们可以看到,这个得出的一个结论是授权过滤器不管是什么应用范围的都是优于行为过滤器的,而在同一种类型的过滤器中是根据应用范围来确定执行顺序的,这个跟下面的浏览器里的内容有点关系,浏览器里显示的就是所有过滤器在排序后的管道里的样子,可以看到管道里单纯的就是按照应用范围的级别来排序的,至于这个过滤器是什么类型在处理排序的时候则是一点都不关心的。

 

过滤器执行过程-代码分析

首先看一下如下示意图,可以代表了在控制器执行的过程中过滤器的执行过程。

2

wKioL1QVgJaycworAALwTSFI6Pw560.jpg

上面通过示例来说明了过滤器的执行过程,现在我们来看一下在框架的源码中是什么样的,因为在过滤器执行过程中还包含了其它方面的知识点,所以这个是迟早都要看的,下面我们就来看一下吧。

代码1-5

1
2
3
4
     returnInvokeActionWithExceptionFilters(InvokeActionWithAuthorizationFilters(actionContext, cancellationToken, authorizationFilters, ()=>actionDescriptor.ActionBinding.ExecuteBindingAsync(actionContext, cancellationToken).Then<HttpResponseMessage>( delegate  {
             this ._modelState=actionContext.ModelState;
             returnInvokeActionWithActionFilters(actionContext, cancellationToken, actionFilters, () =>controllerServices.GetActionInvoker().InvokeActionAsync(actionContext, cancellationToken))();
         }, newCancellationToken(),  false ))(), actionContext, cancellationToken, exceptionFilters);


在代码1-5中涉及到三个静态方法,我们先来看一下:

InvokeActionWithExceptionFilters()

InvokeActionWithAuthorizationFilters()

InvokeActionWithActionFilters()

示例代码如下:

代码1-6

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
    internalstaticTask<HttpResponseMessage>InvokeActionWithExceptionFilters(Task<HttpResponseMessage>actionTask, HttpActionContextactionContext, CancellationTokencancellationToken, IEnumerable<IExceptionFilter>filters)
    {
         returnactionTask.Catch<HttpResponseMessage>( delegate  (CatchInfo<HttpResponseMessage>info) {
             HttpActionExecutedContextexecutedContext=newHttpActionExecutedContext(actionContext, info.Exception);
             filters=filters.Reverse<IExceptionFilter>();
             IEnumerable<Task>asyncIterator=fromfilterinfiltersselectfilter.ExecuteExceptionFilterAsync(executedContext, cancellationToken);
             boolrunSynchronously= true ;
             Task<HttpResponseMessage>task=TaskHelpers.Iterate(asyncIterator, cancellationToken,  true ).Then<HttpResponseMessage>( delegate  {
                 if  (executedContext.Response!= null )
                 {
                     returnTaskHelpers.FromResult<HttpResponseMessage>(executedContext.Response);
                 }
                 returnTaskHelpers.FromError<HttpResponseMessage>(executedContext.Exception);
             }, newCancellationToken(), runSynchronously);
             returninfo.Task(task);
         }, newCancellationToken());
}


代码1-7

1
2
3
4
5
    internalstaticFunc<Task<HttpResponseMessage>>InvokeActionWithAuthorizationFilters(HttpActionContextactionContext, CancellationTokencancellationToken, IEnumerable<IAuthorizationFilter>filters, Func<Task<HttpResponseMessage>>innerAction)
    {
         filters=filters.Reverse<IAuthorizationFilter>();
         returnfilters.Aggregate<IAuthorizationFilter, Func<Task<HttpResponseMessage>>>(innerAction, (continuation, filter) => () =>filter.ExecuteAuthorizationFilterAsync(actionContext, cancellationToken, continuation));
}


代码1-8

1
2
3
4
5
    internalstaticFunc<Task<HttpResponseMessage>>InvokeActionWithActionFilters(HttpActionContextactionContext, CancellationTokencancellationToken, IEnumerable<IActionFilter>filters, Func<Task<HttpResponseMessage>>innerAction)
    {
         filters=filters.Reverse<IActionFilter>();
         returnfilters.Aggregate<IActionFilter, Func<Task<HttpResponseMessage>>>(innerAction, (continuation, filter) => () =>filter.ExecuteActionFilterAsync(actionContext, cancellationToken, continuation));
}


这里我们先看代码1-5表示了过滤器执行的所有过程,突然的看起来这1-5代码的可读性太低了,可能是跟我水平的关系,我看起来很是吃力也比较烦躁,不过这个烂骨头也要啃阿,放过去可能就少学会一点东西。

首先我们看到代码1-5中调用了InvokeActionWithExceptionFilters()方法,也就是代码1-6,那我们就看看这个InvokeActionWithExceptionFilters()方法,在个InvokeActionWithExceptionFilters()方法中有四个参数,第一个参数是Task<HttpResponseMessage>类型的,这里打住不往下看了,回到代码1-5中调用个InvokeActionWithExceptionFilters()方法的时候,我们看代码的最后部分依次往前推,最后发现

代码1-9

1
2
3
4
InvokeActionWithAuthorizationFilters(actionContext, cancellationToken, authorizationFilters, ()=>actionDescriptor.ActionBinding.ExecuteBindingAsync(actionContext, cancellationToken).Then<HttpResponseMessage>( delegate  {
             this ._modelState=actionContext.ModelState;
             returnInvokeActionWithActionFilters(actionContext, cancellationToken, actionFilters, () =>controllerServices.GetActionInvoker().InvokeActionAsync(actionContext, cancellationToken))();
         }, newCancellationToken(),  false ))(),


发现代码1-9的部分就是InvokeActionWithExceptionFilters()方法的参数,我们看命名也都知道InvokeActionWithExceptionFilters()方法执行的是异常过滤器的内容,第一个参数类型也说过了是Task<HttpResponseMessage>说明在这之前操作已经处理完成了不管是成功了还是有异常了咱先不管,反正代码1-9最后生成返回的就是Task<HttpResponseMessage>类型的实例,那我们就来拆开代码1-9.

从代码1-9中可以看到首先调用的是代码1-7的内容也就是调用了InvokeActionWithAuthorizationFilters()方法,我们看一下代码1-7.

首先代码1-7中的方法有四个参数(HttpActionContext actionContext,CancellationToken cancellationToken, IEnumerable<IAuthorizationFilter>filters, Func<Task<HttpResponseMessage>> innerAction),第一个控制器方法执行上下文对象,跟HttpControllerContext性质都是一样的,不说这个,第二个CancellationToken用于并行开发在并行的任务中,可以把这个类型想象成一个钩子,你可以设置这个钩子的状态和行为,在任务中遇到你的钩子会根据你的钩子做一些操作可以是继续任务可以是终止任务额外再执行一些其他操作(不知道理解的对不对没深入过,有误的话望大家指正谢谢),至于第三个参数,就是授权过滤器集合类型了,在上面说到的FilterGrouping类型中的AuthorizationFilters属性就是用在这里,第四个参数就比较重要了,这是一个返回Task<HttpResponseMessage>类型的委托,现在我们把代码1-9也就是调用了InvokeActionWithAuthorizationFilters()方法的代码中的第四个参数剥出来,然后再看下面的代码。

代码1-10

1
2
3
4
5
InvokeActionWithAuthorizationFilters
(
actionContext, 
cancellationToken, 
authorizationFilters,)()


从上面说的也知道现在的代码1-10的部分只是返回一个Task<HttpResponseMessage>类型的实例作为代码1-6的第一个参数,按照这样的思路我们看一下剥离出来的第四个参数。

代码1-11

1
2
3
4
() =>actionDescriptor.ActionBinding.ExecuteBindingAsync(actionContext, cancellationToken).Then<HttpResponseMessage>( delegate  {
             this ._modelState=actionContext.ModelState;
             returnInvokeActionWithActionFilters(actionContext, cancellationToken, actionFilters, () =>controllerServices.GetActionInvoker().InvokeActionAsync(actionContext, cancellationToken))();
         }, newCancellationToken(),  false )


在代码1-11里主要会先调用actionDescriptorActionBinding属性下的ExecuteBindingAsync()方法,这里的方法就是Model绑定Model验证所在的地方了这个后面的篇幅会讲,有的朋友会发现ExecuteBindingAsync()方法返回的是Task类型,跟上面所说的所需参数的类型是Fun<Task<HttpResponseMessage>>,而这里明显就是Fun<Task>,是不符合的,而且按照逻辑上说也不符合阿,在授权过滤器执行完毕后应该是行为过滤器的执行阿,这里就涉及到了一个Task的扩展方法调用,就是Then<>()方法了。

代码1-12

1
2
3
4
internalstaticTask<TOuterResult>Then<TOuterResult>(thisTasktask, Func<Task<TOuterResult>>continuation, CancellationTokencancellationToken=newCancellationToken(), boolrunSynchronously= false )
{
    returntask.ThenImpl<Task, TOuterResult>(t=>continuation(), cancellationToken, runSynchronously);
}


用有扩展方法的类型是私有的结构类型,这里就不往下深入了,就在通过这里将Task转换成Task<HttpResponseMessage>类型的。最后我们在拆一下把这个匿名委托从代码1-11里面剥出来。

代码1-13

1
2
3
4
delegate  {
             this ._modelState=actionContext.ModelState;
             returnInvokeActionWithActionFilters(actionContext, cancellationToken, actionFilters, () =>controllerServices.GetActionInvoker().InvokeActionAsync(actionContext, cancellationToken))();
         }


看到这里有actionContext.ModelState属性值表示Model验证的结果值,而这个this._modelStatethis就是当前的ApiController_modelState字段对应的是ApiController类型中的ModelState值,在这之后调用最后的1-8代码,在上面的1-13中我们可以看到最后是由什么对象去执行最后的操作的,这个一系列的过程后面篇幅会讲解到。

在这些所有都执行完毕了之后才会执行到代码1-6,最后就是形成最后的代码1-5那样。





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





相关文章
|
28天前
|
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后的结果处理。此外,还提供了运行结果的截图和参考文档链接,帮助开发者更好地理解和应用该接口。
104 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刀额度,助您轻松上手!
137 2
|
9月前
|
Java API 数据库
构建RESTful API已经成为现代Web开发的标准做法之一。Spring Boot框架因其简洁的配置、快速的启动特性及丰富的功能集而备受开发者青睐。
【10月更文挑战第11天】本文介绍如何使用Spring Boot构建在线图书管理系统的RESTful API。通过创建Spring Boot项目,定义`Book`实体类、`BookRepository`接口和`BookService`服务类,最后实现`BookController`控制器来处理HTTP请求,展示了从基础环境搭建到API测试的完整过程。
136 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 等实时通信协议,具备自动验证、自动过滤器等丰富功能,适合快速搭建高性能、可扩展的服务端应用。
508 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 应用生成工具,支持通过文本描述快速生成代码,并提供实时代码编辑和预览功能,简化开发流程。
323 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应用防火墙

热门文章

最新文章