基于 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,一经查实,立即删除!

相关文章

CentOS 6.9通过RPM安装EPEL源(http://dl.fedoraproject.org)

另类的装法&#xff0c;通过RPM包直接安装 wget http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm && rpm -ivh epel-release-6-8.noarch.rpm 可以发现上面的地址可以找到非6以外的包&#xff08;http://dl.fedoraproject.org&#xff09;

虚拟机防火墙

1.即时生效&#xff0c;重启后失效 开启&#xff1a;service iptables start 关闭&#xff1a;service iptables stop 2 重启后生效 开启&#xff1a;chkconfig iptables on 关闭&#xff1a;chkconfig iptables off 注意&#xff1a;需要用root用户执行此操作转载于:https://w…

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

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

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

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

如何在Jupyter Notebook中使用在anaconda中创建的虚拟环境

如何在Jupyter Notebook中使用在anaconda中创建的虚拟环境 1、创建虚拟环境并激活 conda create -n 虚拟环境名 python 3.8 conda activate 虚拟环境名 2、在虚拟环境中安装ipykernel pip install ipykernel 使用ipykernel生成虚拟环境的kernel python -m ipykernel insta…

BZOJ1823:[JSOI2010]满汉全席——题解

https://www.lydsy.com/JudgeOnline/problem.php?id1823 https://www.luogu.org/problemnew/show/P4171 题面太长啦就不粘过来啦&#xff01; 裸的2-SAT用来练板子的。 显然属于“a和b之间必须选一种”模型&#xff0c;只要a向b连边&#xff0c;b向a连边即可。 &#xff08;被…

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

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

codevs1079 回家

题目描述 Description现在是晚餐时间,而母牛们在外面分散的牧场中。 农民约翰按响了电铃,所以她们开始向谷仓走去。 你的工作是要指出哪只母牛会最先到达谷仓(在给出的测试数据中,总会有且只有一只最快的母牛)。 在挤奶的时候(晚餐前),每只母牛都在她自己的牧场上,一些牧场上可…

什么是xmlschema

XML Schema定义&#xff08;XML Schema Definition,XSD&#xff09;是一套W3C标准,用于基于XML的称为XML Schema的类型系统.用于定义的语言是一种称为XML模式定义语言&#xff08;XML Schema Definition Language&#xff09;的XML语法.Web 服务使用XML作为表示消息和数据的底层…

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

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

如何管理跨部门的沟通与协作?

俗话说“磨刀不误砍柴工”&#xff0c;选对方法&#xff0c;再复杂的事也能事半功倍。在新营销时代&#xff0c;效率为王&#xff0c;而高效率的背后&#xff0c;则是给力的技术工具与合理的工作方式。 企业级服务的兴起&#xff0c;让人们看到了信息化技术的潜力&#xff0c;从…

启动Jupyter Notebook时出现Kernel error错误的解决方法

启动Jupyter Notebook时出现Kernel error错误的解决方法 方法如下&#xff1b; 1、打开Anaconda Prompt&#xff0c;然后输入jupyter kernelspec list,查看一下 2、打开anaconda的安装目录找到E:\Anaconda3\anaconda3\share\jupyter\kernels\python3下面的kernel.json&#x…

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

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

Ubuntu16.04 + caffe-ssd + [CPU_ONLY] + KITTI 训练总结

本次训练主要参考&#xff1a;http://blog.csdn.net/jesse_mx/article/details/65634482 感谢 Jesse_Mx &#xff0c;帮助了我很多。 坑一【openCV未安装成功】&#xff1a; openCV未安装成功会导致各种莫名的问题&#xff0c;比如&#xff1a;“No module named cv2”问题。 然…

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

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

python中字典长度可变吗_Python:如何给字典分配一个长度可变的列表值?

我试图在100个2D numpy数组中定位质心&#xff0c;如下所示&#xff1a;array([[ 0.216, 0.24 , 0.244, ..., 0.679, 0.684, 0.707],[ 0.23 , 0.229, 0.238, ..., 0.675, 0.676, 0.695],[ 0.221, 0.238, 0.24 , ..., 0.669, 0.677, 0.684],...,[ 0.937, 0.925, 0.923, ..., 0.7…

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

首先下载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 …

【Android Studio】查看源码时提示“throw new RuntimeException(Stub!)”

如题…… 详细问题及解决方法&#xff1a;http://blog.csdn.net/u010917495/article/details/51234179 转载于:https://www.cnblogs.com/jaxer/p/7071431.html

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

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