基于 Filter 实现条件路由

基于 filter 实现条件路由

Intro

在我们的项目有几个测试用的接口,有的接口我们往往不想在生产环境上使用,于是会在代码里判断当前环境是不是生产环境,如果不是生产环境才允许执行,否则就返回一个错误,这样的接口多了之后就会发现很多重复的代码,我们此时就可以使用一个 filter 来实现 API 接口的检查,如果是生产环境就不执行 API 接口的逻辑

Filter V1

MVC filter 有几种类型,AuthorizationFilterResourceFilterActionFilterResultFilterExceptionFilter, 首先我们要选择合适的类型,最合适的莫过于 ResourceFilterActionFilter,可能大多小伙伴对于 ActionFilter 更为熟悉一些,但是我觉得这种场景下 ResourceFilter 更好一些,从 MVC filter 的执行流程上来说,会依次执行 AuthorizationFilterResourceFilterActionFilter,而我们的条件并非一种授权,所以个人感觉 ResourceFilter 更合适一些,我们可以使用 IAsyncResourceFilter 来实现,实现代码如下:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public sealed class NonProductionOnlyFilter : Attribute, IAsyncResourceFilter
{public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next){var environment = context.HttpContext.RequestServices.GetRequiredService<IWebHostEnvironment>();if (environment.IsProduction()){context.Result = new NotFoundResult();}else{await next();}}
}

Filter V2

为了更加的通用,我们可以把检查的逻辑和返回值逻辑封装成一个委托

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class ConditionalFilter : Attribute, IAsyncResourceFilter
{public Func<HttpContext, bool> ConditionFunc { get; init; } = _ => true;public Func<HttpContext, IActionResult> ResultFactory { get; init; } = _ => new NotFoundResult();public virtual async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next){var condition = ConditionFunc.Invoke(context.HttpContext);if (condition){await next();}else{var result = ResultFactory.Invoke(context.HttpContext);context.Result = result;}}
}

再在这个 ConditionalFilter 的基础上实现上面的逻辑:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
public sealed class NonProductionEnvironmentFilter : ConditionalFilter
{public NonProductionEnvironmentFilter(){ConditionFunc = c => c.RequestServices.GetRequiredService<IWebHostEnvironment>().IsProduction() == false;}
}

看起来是不是简单了很多,对于别的情况也比较容易扩展,比如我们实现一个指定环境生效的条件

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
public sealed class EnvironmentFilter : ConditionalFilter
{public EnvironmentFilter(params string[] environmentNames){Guard.NotNull(environmentNames);var allowedEnvironments = environmentNames.ToHashSet(StringComparer.OrdinalIgnoreCase);ConditionFunc = c =>{var env = c.RequestServices.GetRequiredService<IWebHostEnvironment>().EnvironmentName;return allowedEnvironments.Contains(env);};}
}

Filter V3

在前面的文章中我们有提到在 .NET 7 中针对于 Minimal API,引入了 EndpointFilter,我们也可以为我们的 ConditionalFilter 添加 EndpointFilter 的支持

public class ConditionalFilter : Attribute, IAsyncResourceFilter
#if NET7_0_OR_GREATER, IEndpointFilter
#endif{public Func<HttpContext, bool> ConditionFunc { get; init; } = _ => true;public Func<HttpContext, object> ResultFactory { get; init; } = _ =>
#if NET7_0_OR_GREATERResults.NotFound()
#elsenew NotFoundResult()
#endif;public virtual async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next){var condition = ConditionFunc.Invoke(context.HttpContext);if (condition){await next();}else{var result = ResultFactory.Invoke(context.HttpContext);context.Result = result switch{IActionResult actionResult => actionResult,IResult httpResult => new HttpResultActionResultAdapter(httpResult),_ => new OkObjectResult(result)};}}
#if NET7_0_OR_GREATERpublic virtual async ValueTask<object> InvokeAsync(EndpointFilterInvocationContext context, EndpointFilterDelegate next){var result = ConditionFunc.Invoke(context.HttpContext);if (result){return await next(context);}return ResultFactory.Invoke(context.HttpContext);}
#endif
}

这里有个需要注意的地方就是 EndpointFilter 的返回和 Resource filter 的返回值不同,返回的类型不是 IActionResult 而且不能正确的处理 IActionResult 类型,针对 IResult 会有处理,所以我们针对 .NET 7 及以上返回的是 IResult 类型,在 ResourceFilter 中处理逻辑中针对 IResult 再转成了 IActionResult, 也就是上面的 HttpResultActionResultAdapter,实现也很简单,实现如下:

internal sealed class HttpResultActionResultAdapter : IActionResult
{private readonly IResult _result;public HttpResultActionResultAdapter(IResult result){_result = result;}public Task ExecuteResultAsync(ActionContext context){return _result.ExecuteAsync(context.HttpContext);}
}

Demo

测试代码分为 Minimal API 的 endpoint API 和 MVC controller,示例代码如下:

var envGroup = app.MapGroup("/env-test");
envGroup.Map("/dev", () => "env-test").AddEndpointFilter(new EnvironmentFilter(Environments.Development));
envGroup.Map("/prod", () => "env-test").AddEndpointFilter(new EnvironmentFilter(Environments.Production));
[HttpGet("EnvironmentFilterTest/Dev")]
[EnvironmentFilter("Development")]
//[EnvironmentFilter("Production")]
public IActionResult EnvironmentFilterDevTest()
{return Ok(new { Title = ".NET is amazing!" });
}[HttpGet("EnvironmentFilterTest/Prod")]
[EnvironmentFilter("Production")]
public IActionResult EnvironmentFilterProdTest()
{return Ok(new { Title = ".NET is amazing!" });
}

访问我们的 API 来测试一下返回结果:

bd0b36ac0d3eaaae47fda8f7d0611e48.png

Minimal API

96ab29ab5ddd872c9bd124a90ba93e4e.png

controller

我们启动的时候默认的环境是 Development,所以 Production 返回的都是 404,而 Development 相关的 API 则是正常返回了~

References

  • https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/filters

  • https://github.com/WeihanLi/WeihanLi.Web.Extensions

  • https://github.com/WeihanLi/WeihanLi.Web.Extensions/tree/dev/samples/WeihanLi.Web.Extensions.Samples

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/283276.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ORM框架通过映射(反射)获取数据库的数据

ORM&#xff08;Object Relational Mapping&#xff09;框架采用元数据来描述对象一关系映射细节&#xff0c;元数据一般采用XML格式&#xff0c;并且存放在专门的对象一映射文件中。只要提供了持久化类与表的映射关系&#xff0c;ORM框架在运行时就能参照映射文件的信息&#…

找不到r低版本_R 语言与数据挖掘直播班开始招生,生信分析帮你发高分文章

数据单薄很难支撑文章内容&#xff1f;数据有了不知道怎么处理作出高级的图片&#xff1f;这个时候需要的是生信分析——深度的数据挖掘和分析处理&#xff0c;可以帮助临床医生通过数据处理得到自己想要的信息&#xff0c;更快速地发文章。学习哪种生信分析的工具&#xff1f;…

读两本敦煌书杂记-敦煌由盛转衰(二)

公元420-589年&#xff0c;中国分为南北两个部分&#xff08;史称魏晋南北朝&#xff0c;由西晋末年八王之乱引起&#xff0c;北方游牧少数民族趁机侵扰中原&#xff0c;并先后建立多个少数民族政权&#xff0c;又称“五胡乱华”。“五胡”主要指匈奴、鲜卑、羯、羌、氐五个胡人…

第三方app_为什么第三方APP不能下载呢?

这些年科学技术发展日新月异&#xff0c;信息技术和网络技术也层出不穷&#xff0c;大众出行工具的汽车电器化集成度越来越高&#xff0c;汽车上娱乐主机的智能化和网络化程度也越来越高&#xff0c;汽车娱乐主机也成了人民除手机外的第二个娱乐工具&#xff0c;用惯了手机娱乐…

WPF效果第一百九十七篇之Path范围内拖拽

前面效果中分享了彩色马蹄图的效果;这不今天再次在马蹄图的基础上,实现只能在Path内的拖拽效果;闲话不多扯直接看效果:1、关于拖拽顶点实现色域范围选择,参考:https://www.codeproject.com/Tips/828310/The-simplest-WPF-diagram-designer-part2、通过Blend绘制了色度图中间区域…

PHP面向对象常见的关键字和魔术方法

在PHP5的面向对象程序设计中提供了一些常见的关键字&#xff0c;用来修饰类、成员属性或成员方法&#xff0c;使他们具有特定的功能&#xff0c;例如final、static、const等关键字。还有一些比较实用的魔术方法&#xff0c;用来提高类或对象的应用能力&#xff0c;例如__call()…

如何在论文中自动生成标准的参考文献格式

首先下载EndNote软件&#xff0c;word中会自动显示EndNote选项 选择EndNote 选择导出会下载一个txt文件 打开EndNote中向下的箭头导入&#xff08;从文件导入文献到库中&#xff09;找到刚才下载的txt文件 点击选择按键找到txt文件 选择打开即可 选择导入 选择导入的内容…

PrincetonAlgorithm I - Assignment2 Deques and Randomized Queues

Programming Assignment2 - Deque and Randomized Queues Review Assignment Specification 课程笔记 Subtext: Modular Programming Stacks and Queues are fundamental data types Value: collection of objectsBasic Operation: insert, remove, iterate.Difference: which …

TCP短连接产生大量TIME_WAIT导致无法对外建立新TCP连接的原因及解决方法—基础知识篇...

最近遇到一个线上报警&#xff1a;服务器出现大量TIME_WAIT导致其无法与下游模块建立新HTTP连接&#xff0c;在解决过程中&#xff0c;通过查阅经典教材和技术文章&#xff0c;加深了对TCP网络问题的理解。作为笔记&#xff0c;记录于此。 备注&#xff1a;本文主要介绍…

开源许可证,欢迎来到云时代

出品 | OSC开源社区&#xff08;ID&#xff1a;oschina2013)作者 | 唐建法前言开源许可证从最早的 GPL 开始&#xff0c; 逐渐演进到 GPLv2 和 v3&#xff0c;中间还有 Apache、MPL、AGPL、LGPL 等&#xff0c;但是近几年来有一批新的许可证的出现&#xff0c;引起了社区的一些…

selenium - Select类 - 下拉框

WebDriver提供了Select类来处理下拉框。 如百度搜索设置的下拉框&#xff0c;如下图&#xff1a; from selenium import webdriver from selenium.webdriver.support.select import Select from time import sleepdriver webdriver.Chrome() driver.implicitly_wait(10) drive…

.NET 7 预览版 7

点击上方蓝字关注我们&#xff08;本文阅读时间&#xff1a;12分钟)今天我们发布了 .NET 7 预览版 7。这是 .NET 7 的最后一个预览版&#xff0c;下一个版本将是我们的第一个候选版本 &#xff08;RC&#xff09;。.NET Conf 2022 的日期已经公布&#xff01;请于 2022 年 11 月…

android--------volley之网络请求和图片加载

为什么80%的码农都做不了架构师&#xff1f;>>> Volley是 Google 推出的 Android 异步网络请求框架和图片加载框架。 Volley的特性 封装了的异步的请求API。Volley 中大多是基于接口的设计&#xff0c;可配置性强。一个优雅和稳健的请求队列&#xff0c;一定程度符…

经典算法学习——冒泡排序

冒泡排序是我们学习的第一种排序算法。应该也算是最简单、最经常使用的排序算法了。无论怎么说。学会它是必定的。今天我们就用C语言来实现该算法。演示样例代码已经上传至&#xff1a;https://github.com/chenyufeng1991/BubbleSort算法描写叙述例如以下&#xff1a;&#xff…

Mybatis之设计模式之装饰者模式

了解&#xff0c;什么是装饰者模式? 1.定义 装饰模式是在不必改变原类文件和使用继承的情况下&#xff0c;动态地扩展一个对象的功能。它是通过创建一个包装对象&#xff0c;也就是装饰来包裹真实的对象。 2.特点 1 装饰对象和真实对象有相同的接口。这样客户端对象就能以和真…

一天掌握Android JNI本地编程 快速入门

一、JNI&#xff08;Java Native Interface&#xff09; 1、什么是JNI&#xff1a;JNI(Java Native Interface):java本地开发接口JNI是一个协议&#xff0c;这个协议用来沟通java代码和外部的本地代码(c/c) 外部的c/c代码也可以调用java代码2、为什么使用JNI&#xff1a;效率上…

[转]CentOS 7忘记root密码解决办法

转自&#xff1a;http://www.linuxidc.com/Linux/2016-08/134034.htm 亲测可用&#xff01; CentOS 7 root密码的重置方式和CentOS 6完全不一样&#xff0c;CentOS 7与之前的版本6变化还是比较大的&#xff0c;以进入单用户模式修改root密码为例。 1.重启开机按esc 2.按e 3.编…

美链BEC合约漏洞技术分析

这两天币圈链圈被美链BEC智能合约的漏洞导致代币价值几乎归零的事件刷遍朋友圈。这篇文章就来分析下BEC智能合约的漏洞 <!-- more --> 漏洞攻击交易 我们先来还原下攻击交易&#xff0c;这个交易可以在这个链接查询到。我截图给大家看一下&#xff1a; 攻击者向两个账号转…

vue 公众号扫描_vue编写微信公众号打开相机功能

vue编写微信公众号打开相机功能&#xff0c;什么都不多说直接上代码页面布局代码class"previewer-demo-img":key"index":src"item.src"width"100"click"previewImg(index)">1.微信config初始化前端代码initWxConfig() {l…

SQL Server-聚焦NOT IN VS NOT EXISTS VS LEFT JOIN...IS NULL性能分析(十八)

前言 本节我们来综合比较NOT IN VS NOT EXISTS VS LEFT JOIN...IS NULL的性能&#xff0c;简短的内容&#xff0c;深入的理解&#xff0c;Always to review the basics。 NOT IN、NOT EXISTS、LEFT JOIN...IS NULL性能分析 我们首先创建测试表 USE TSQL2012 GOCREATE SCHEMA [c…