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






相关文章
|
6天前
|
开发框架 监控 .NET
Visual Basic的Web服务和REST API开发指南
【4月更文挑战第27天】本文探讨了使用Visual Basic(VB.NET)构建Web服务和RESTful API的方法。首先介绍了Web服务的基础和REST API的概念,然后阐述了.NET Framework与.NET Core/.NET 5+对VB.NET的支持,以及ASP.NET Core在Web开发中的作用。接着,详细讲解了创建RESTful API的步骤,包括控制器与路由设置、模型绑定与验证,以及返回响应。此外,还讨论了安全措施、测试方法、部署选项和监控策略。最后强调,VB.NET开发者可以通过ASP.NET Core涉足现代Web服务开发,拓宽技术领域。
|
6天前
|
API 网络安全 数据安全/隐私保护
.NET邮箱API发送邮件的方法有哪些
本文介绍了.NET开发中使用邮箱API发送邮件的方法,包括SmtpClient类发送邮件、MailMessage类创建邮件消息、设置SmtpClient属性、同步/异步发送、错误处理、发送HTML格式邮件、带附件邮件以及多人邮件。AokSend提供高触达发信服务,适用于大规模验证码发送场景。了解这些技巧有助于开发者实现高效、可靠的邮件功能。
|
6天前
|
弹性计算 JSON Shell
基于Web API的自动化信息收集和整理
【4月更文挑战第30天】
21 0
|
3天前
|
缓存 监控 API
利用Python构建高性能的Web API后端服务
随着微服务架构的普及和RESTful API的广泛应用,构建高性能、可扩展的Web API后端服务变得尤为重要。本文将探讨如何利用Python这一强大且灵活的语言,结合现代Web框架和工具,构建高效、可靠的Web API后端服务。我们将分析Python在Web开发中的优势,介绍常用的Web框架,并通过实际案例展示如何设计并实现高性能的API服务。
|
6天前
|
JSON 安全 API
【专栏】四种REST API身份验证方法:基本认证、OAuth、JSON Web Token(JWT)和API密钥
【4月更文挑战第28天】本文探讨了四种REST API身份验证方法:基本认证、OAuth、JSON Web Token(JWT)和API密钥。基本认证简单但不安全;OAuth适用于授权第三方应用;JWT提供安全的身份验证信息传递;API密钥适合内部使用。选择方法时需平衡安全性、用户体验和开发复杂性。
|
6天前
|
缓存 前端开发 API
toapi,一个强大的 Python Web API库!
toapi,一个强大的 Python Web API库!
29 5
|
6天前
|
JSON API 数据库
解释如何在 Python 中实现 Web 服务(RESTful API)。
在Python中实现Web服务(RESTful API)涉及选择框架(如Flask、Django、FastAPI),定义路由及处理函数(对应HTTP请求方法),处理请求,构建响应和启动服务器。以下是一个使用Flask的简单示例:定义用户列表,通过`@app.route`装饰器设置GET和POST请求处理函数,返回JSON响应,并用`app.run()`启动服务器。实际API会包含更复杂的逻辑和错误处理。
18 1
|
6天前
|
XML JSON API
通过Flask框架创建灵活的、可扩展的Web Restful API服务
通过Flask框架创建灵活的、可扩展的Web Restful API服务
|
6天前
|
缓存 监控 API
Python Web框架FastAPI——一个比Flask和Tornada更高性能的API框架
Python Web框架FastAPI——一个比Flask和Tornada更高性能的API框架
63 0
|
6天前
|
JSON API 数据格式
构建高效Python Web应用:Flask框架与RESTful API设计实践
【2月更文挑战第17天】在现代Web开发中,轻量级框架与RESTful API设计成为了提升应用性能和可维护性的关键。本文将深入探讨如何使用Python的Flask框架来构建高效的Web服务,并通过具体实例分析RESTful API的设计原则及其实现过程。我们将从基本的应用架构出发,逐步介绍如何利用Flask的灵活性进行模块化开发,并结合请求处理、数据验证以及安全性考虑,打造出一个既符合标准又易于扩展的Web应用。
695 4

热门文章

最新文章