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:,如需转载请自行联系原作者





相关文章
|
15天前
|
Java API 数据库
构建RESTful API已经成为现代Web开发的标准做法之一。Spring Boot框架因其简洁的配置、快速的启动特性及丰富的功能集而备受开发者青睐。
【10月更文挑战第11天】本文介绍如何使用Spring Boot构建在线图书管理系统的RESTful API。通过创建Spring Boot项目,定义`Book`实体类、`BookRepository`接口和`BookService`服务类,最后实现`BookController`控制器来处理HTTP请求,展示了从基础环境搭建到API测试的完整过程。
31 4
|
17天前
|
XML JSON API
ServiceStack:不仅仅是一个高性能Web API和微服务框架,更是一站式解决方案——深入解析其多协议支持及简便开发流程,带您体验前所未有的.NET开发效率革命
【10月更文挑战第9天】ServiceStack 是一个高性能的 Web API 和微服务框架,支持 JSON、XML、CSV 等多种数据格式。它简化了 .NET 应用的开发流程,提供了直观的 RESTful 服务构建方式。ServiceStack 支持高并发请求和复杂业务逻辑,安装简单,通过 NuGet 包管理器即可快速集成。示例代码展示了如何创建一个返回当前日期的简单服务,包括定义请求和响应 DTO、实现服务逻辑、配置路由和宿主。ServiceStack 还支持 WebSocket、SignalR 等实时通信协议,具备自动验证、自动过滤器等丰富功能,适合快速搭建高性能、可扩展的服务端应用。
75 3
|
1天前
|
JSON API 数据格式
如何使用Python和Flask构建一个简单的RESTful API。Flask是一个轻量级的Web框架
本文介绍了如何使用Python和Flask构建一个简单的RESTful API。Flask是一个轻量级的Web框架,适合小型项目和微服务。文章从环境准备、创建基本Flask应用、定义资源和路由、请求和响应处理、错误处理等方面进行了详细说明,并提供了示例代码。通过这些步骤,读者可以快速上手构建自己的RESTful API。
9 2
|
11天前
|
监控 负载均衡 API
Web、RESTful API 在微服务中有哪些作用?
在微服务架构中,Web 和 RESTful API 扮演着至关重要的角色。它们帮助实现服务之间的通信、数据交换和系统的可扩展性。
32 2
|
17天前
|
人工智能 搜索推荐 API
用于企业AI搜索的Bocha Web Search API,给LLM提供联网搜索能力和长文本上下文
博查Web Search API是由博查提供的企业级互联网网页搜索API接口,允许开发者通过编程访问博查搜索引擎的搜索结果和相关信息,实现在应用程序或网站中集成搜索功能。该API支持近亿级网页内容搜索,适用于各类AI应用、RAG应用和AI Agent智能体的开发,解决数据安全、价格高昂和内容合规等问题。通过注册博查开发者账户、获取API KEY并调用API,开发者可以轻松集成搜索功能。
|
22天前
|
开发框架 .NET API
Windows Forms应用程序中集成一个ASP.NET API服务
Windows Forms应用程序中集成一个ASP.NET API服务
77 9
|
23天前
|
存储 开发框架 .NET
.NET 8 实现无实体库表 API 部署服务
【10月更文挑战第12天】在.NET 8中,可通过以下步骤实现无实体库表的API部署:首先安装.NET 8 SDK及开发工具,并选用轻量级Web API框架如ASP.NET Core;接着创建新项目并设计API,利用内存数据结构模拟数据存储;最后配置项目设置并进行测试与部署。此方法适用于小型项目或临时解决方案,但对于大规模应用仍需考虑持久化存储以确保数据可靠性与可扩展性。
|
2月前
|
开发框架 监控 前端开发
在 ASP.NET Core Web API 中使用操作筛选器统一处理通用操作
【9月更文挑战第27天】操作筛选器是ASP.NET Core MVC和Web API中的一种过滤器,可在操作方法执行前后运行代码,适用于日志记录、性能监控和验证等场景。通过实现`IActionFilter`接口的`OnActionExecuting`和`OnActionExecuted`方法,可以统一处理日志、验证及异常。创建并注册自定义筛选器类,能提升代码的可维护性和复用性。
|
14天前
|
移动开发 前端开发 JavaScript
前端开发实战:利用Web Speech API之speechSynthesis实现文字转语音功能
前端开发实战:利用Web Speech API之speechSynthesis实现文字转语音功能
81 0
|
25天前
|
监控 安全 API
Docker + .NET API:简化部署和扩展
Docker + .NET API:简化部署和扩展
33 0