2021年5月12日星期三

ASP.NET Core 3.1 WebAPI 自定义ActionFilter过滤器

ASP.NET Core Web API 自定义ActionFilter过滤器

原文地址:https://www.cnblogs.com/jingjiangtao/p/14711003.html

 准备工作

为了演示自定义过滤器,需要新建一个 ASP.NET Core Web API 项目,项目配置可以按照自己的习惯来,也可以参考下面的配置,总之能让项目跑起来就可以。

Startup类:

 public class Startup {  public Startup(IConfiguration configuration)  {   Configuration = configuration;  }  public IConfiguration Configuration { get; }  // This method gets called by the runtime. Use this method to add services to the container.  public void ConfigureServices(IServiceCollection services)  {   services.AddControllers();  }  // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.  public void Configure(IApplicationBuilder app, IWebHostEnvironment env)  {   if (env.IsDevelopment())   {    app.UseDeveloperExceptionPage();   }   app.UseRouting();   app.UseAuthorization();   app.UseEndpoints(endpoints =>   {    endpoints.MapControllers();   });  } }

 

launchSettings.json

{ "$schema": "", "profiles": { "CustomizeActionFilter": {  "commandName": "Project",  "dotnetRunMessages": "true",  "launchBrowser": true,  "launchUrl": "",  "applicationUrl": "",  "environmentVariables": {  "ASPNETCORE_ENVIRONMENT": "Development"  } } }}

 

在Controllers目录下新建SampleController控制器类。这个类只是用来演示,没有业务上的意义:

 public class SampleController : ControllerBase {  [HttpGet("NeedVersionFilter")]  public IActionResult NeedVersionFilter()  {   return Ok("OK: Need Version");  }  [HttpGet("NoNeedVersionFilter")]  public IActionResult NoNeedVersionFilter()  {   return Ok("OK: No Need Version");  } }

 自定义过滤器

接下来开始编写自定义Action Filter。在项目根目录下新建ActionFilters目录,在此目录下新建类VersionCheckAttribute,该类继承自Attribute并实现了IActionFilter接口。继承Attribute可以让自定义过滤器以特性的方式使用,也就是用方括号括起来的形式,也有人叫标签;实现IActionFilter接口可以在请求的不同阶段添加处理逻辑。

 [Serializable, AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)] public class VersionCheckAttribute : Attribute, IActionFilter {  public void OnActionExecuted(ActionExecutedContext context)  {     }  public void OnActionExecuting(ActionExecutingContext context)  {     } }

其中OnActionExecuting方法在请求进入控制器Action之前执行,拦截代码也在这个方法中实现。

为做演示,假设需要实现这样一种拦截器:每个http请求的header中都应该带有自定义的参数version,如果version的值正确,则请求正常进入控制器执行,如果不正确,则直接返回,不再进入控制器。代码如下:

 [Serializable, AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)] public class VersionCheckAttribute : Attribute, IActionFilter {  public void OnActionExecuted(ActionExecutedContext context)  {     }  public void OnActionExecuting(ActionExecutingContext context)  {   if (!context.HttpContext.Request.Headers.ContainsKey("version"))   {    context.Result = new BadRequestObjectResult("Error: incorrect version");    return;   }   string headVersionStr = context.HttpContext.Request.Headers["version"].FirstOrDefault();   if (headVersionStr != "1.0.0")   {    context.Result = new BadRequestObjectResult("Error: incorrect version");    return;   }  } }

首先判断header中有没有version参数,没有的话直接返回错误。如果有version参数,则判断值是否正确,如果不正确也直接返回错误,如果正确,则继续向下执行,请求会进入控制器的Action。给context.Result赋值可以将请求短路,不会再进入控制器的Action中执行,而是直接返回。

接下来在SampleController上应用VersionCheck过滤器,让它过滤控制器中的所有请求:

 [Route("[controller]")] [ApiController] [VersionCheck] // 自定义过滤器 public class SampleController : ControllerBase {  [HttpGet("NeedVersionFilter")]  public IActionResult NeedVersionFilter()  {   return Ok("OK: Need Version");  }  [HttpGet("NoNeedVersionFilter")]  public IActionResult NoNeedVersionFilter()  {   return Ok("OK: No Need Version");  } }

运行项目,用postman请求看看结果:

没有添加自定义header,返回 Error: incorrect version

 

 

 

 

 添加了自定义header,返回正常:

 

 

 

至此,一个简单的Action Filter已经完成了。

排除指定的Action

上面实现的控制器有两个Action,假设有这样一种需求:NeedVersionFilter接口需要过滤版本号,NoNeedVersionFilter接口不需要过滤版本号。这样的话,[VersionCheck]放到SampleController类上就不行了,可以删掉控制器上的[VersionCheck]特性,转而放到NeedVersionFilter方法上,这样就实现了这个需求。

 [Route("[controller]")] [ApiController] public class SampleController : ControllerBase {  [VersionCheck] // 将过滤器放到方法上  [HttpGet("NeedVersionFilter")]  public IActionResult NeedVersionFilter()  {   return Ok("OK: Need Version");  }  [HttpGet("NoNeedVersionFilter")]  public IActionResult NoNeedVersionFilter()  {   return Ok("OK: No Need Version");  } }

但是,如果Controller中的Action非常多,而大部分Action都需要版本过滤器,只有少数几个不需要,用这种形式就要在每个方法上应用[VersionCheck]特性,有点麻烦,还可能漏加。这时候如果把[VersionCheck]应用到Controller上,同时可以排除几个不需要过滤器的方法,写起来会更简洁。这是可以做到的,通过给不需要过滤器的方法做标记,就可以在过滤器中跳过有标记的方法了。

在ActionFilters目录下新建类IgnoreVersionCheckAttribute,继承自Attribute类和IFilterMetadata接口。IFilterMetadata接口没有需要实现的方法,仅作为标记:

 [Serializable, AttributeUsage(AttributeTargets.Method)] public class IgnoreVersionCheckAttribute : Attribute, IFilterMetadata { }

修改VersioncheckAttribute类的代码,让过滤器跳过标记为IgnoreVersionCheck的方法:

 [Serializable, AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)] public class VersionCheckAttribute : Attribute, IActionFilter {  public void OnActionExecuted(ActionExecutedContext context)  {  }  public void OnActionExecuting(ActionExecutingContext context)  {   if (HasIgnoreVersionCheck(context))   {    return;   }   if (!context.HttpContext.Request.Headers.ContainsKey("version"))   {    context.Result = new BadRequestObjectResult("Error: incorrect version");    return;   }   string headVersionStr = context.HttpContext.Request.Headers["version"].FirstOrDefault();   if (headVersionStr != "1.0.0")   {    context.Result = new BadRequestObjectResult("Error: incorrect version");    return;   }  }  private bool HasIgnoreVersionCheck(ActionExecutingContext context)  {   IList<IFilterMetadata> filters = context.Filters;   foreach (IFilterMetadata filter in filters)   {    if (filter is IgnoreVersionCheckAttribute)    {     return true;    }   }   return false;  } }

可以看到,在刚进入Action时就判断是否有IgnoreVersionCheck,如果有,则直接退出过滤器,继续执行Controller中的代码,如果没有则继续执行过滤器。HasIgnoreVersionCheck方法从ActionExecutingContext中拿到当前Action上的所有filter,遍历查找有没有IgnoreVersionCheckAttribute,有则返回true,没有则返回false。

修改SampleController的代码,把[VersionCheck]放到控制器上,在NoNeedVersionFilter方法上添加[IgnoreVersionCheck]

 [Route("[controller]")] [ApiController] [VersionCheck] public class SampleController : ControllerBase {  [HttpGet("NeedVersionFilter")]  public IActionResult NeedVersionFilter()  {   return Ok("OK: Need Version");  }  [IgnoreVersionCheck]  [HttpGet("NoNeedVersionFilter")]  public IActionResult NoNeedVersionFilter()  {   return Ok("OK: No Need Version");  } }

测试一下是否生效。

NeedVersionFilter接口不添加version头:

 

 NeedVersionFilter接口添加version头:

 

 NoNeedVersionFilter不添加version头:

 

 可以看到确实生效了。至此,带排除项的过滤器就完成了。

在过滤器中获取服务

上面的过滤器代码为了方便起见,判断版本号是否正确时直接用了 "1.0.0" 这种硬编码的字符串,实际项目中这个字符串可能是会变化的,最好写在配置文件中。在appsetting.Development.json中添加字段 "VersionFilter" 并赋值:

{ "Logging": {  "LogLevel": {   "Default": "Information",   "Microsoft": "Warning",   "Microsoft.Hosting.Lifetime": "Information"  } }, "VersionFilter": "1.0.0"}

修改VersionCheckAttribute的代码,通过ActionExecutedContext中的属性获取IConfiguration服务,再从IConfiguration实例中获取字符串:

 [Serializable, AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)] public class VersionCheckAttribute : Attribute, IActionFilter {  public void OnActionExecuted(ActionExecutedContext context)  {  }  public void OnActionExecuting(ActionExecutingContext context)  {   if (HasIgnoreVersionCheck(context))   {    return;   }   if (!context.HttpContext.Request.Headers.ContainsKey("version"))   {    context.Result = new BadRequestObjectResult("Error: incorrect version");    return;   }   string headVersionStr = context.HttpContext.Request.Headers["version"].FirstOrDefault();
// 获取配置服务 var configuration = context.HttpContext.RequestServices.GetRequiredService<IConfiguration>(); string confVersionStr = configuration.GetValue<string>("VersionFilter"); if (headVersionStr != confVersionStr) { context.Result = new BadRequestObjectResult("Error: incorrect version"); return; } } private bool HasIgnoreVersionCheck(ActionExecutingContext context) { IList<IFilterMetadata> filters = context.Filters; foreach (IFilterMetadata filter in filters) { if (filter is IgnoreVersionCheckAttribute) { return true; } } return false; } }

这样,一个比较灵活的自定义ActionFilter就完成了。









原文转载:http://www.shaoqun.com/a/738798.html

跨境电商:https://www.ikjzd.com/

houzz:https://www.ikjzd.com/w/236

ifttt:https://www.ikjzd.com/w/956


ASP.NETCoreWebAPI自定义ActionFilter过滤器原文地址:https://www.cnblogs.com/jingjiangtao/p/14711003.html准备工作为了演示自定义过滤器,需要新建一个ASP.NETCoreWebAPI项目,项目配置可以按照自己的习惯来,也可以参考下面的配置,总之能让项目跑起来就可以。Startup类:publicclassStartup{
淘粉吧:https://www.ikjzd.com/w/1725
ifttt:https://www.ikjzd.com/w/956
netporter:https://www.ikjzd.com/w/2132
eBay 跨国退货退款实战及售后常见问题解答,纯干货:https://www.ikjzd.com/tl/14981
回家看见小叔子一丝不挂睡沙发:http://lady.shaoqun.com/a/271672.html
疫情下,你所不了解的亚马逊物流状态:https://www.ikjzd.com/home/119009

没有评论:

发表评论