在Asp.Net Core中使用ModelConvention实现全局过滤器隔离

从何说起

这来自于我把项目迁移到Asp.Net Core的过程中碰到一个问题。在一个web程序中同时包含了MVC和WebAPI,现在需要给WebAPI部分单独添加一个接口验证过滤器IActionFilter,常规做法一般是写好过滤器后给需要的控制器挂上这个标签,高级点的做法是注册一个全局过滤器,这样可以避免每次手动添加同时代码也更好管理。注册全局过滤器的方式为:

 services.AddMvc(options =>{options.Filters.Add(typeof(AccessControlFilter));});

但这样做会带来一个问题,那就是MVC部分控制器也会受影响,虽然可以在过滤器中进行一些判断来区分哪些是MVC Controller哪些是API Controller,但是平白无故给MVC增加这么一个没用的Filter,反正我是不能忍,所以寻找有没有更好的办法来实现这个功能。
于是ModelConvention(可以翻译为模型约定)闪亮登场。

先认识下ApplicationModel

看一下官方文档是怎么描述应用程序模型(ApplicationModel)的:

ASP.NET Core MVC defines an application model representing the components of an MVC app. You can read and manipulate this model to modify how MVC elements behave. By default, MVC follows certain conventions to determine which classes are considered to be controllers, which methods on those classes are actions, and how parameters and routing behave. You can customize this behavior to suit your app's needs by creating your own conventions and applying them globally or as attributes.

简单一点说,ApplicationModel描述了MVC应用中的各种对象和行为,这些内容包含Application、Controller、Action、Parameter、Router、Page、Property、Filter等等,而Asp.Net Core框架本身内置一套规则(Convention)用来处理这些模型,同时也提供了接口给我们自定义约定来扩展模型以实现更符合需要的应用。

和应用程序模型有关的类都定义在命名空间Microsoft.AspNetCore.Mvc.ApplicationModels中,这些模型通过IApplicationModelProvider 构建出来,Asp.Net Core框架提供的默认Provider是DefaultApplicationModelProvider。我们可以编辑这些模型,从而更改它的表现行为,这就要借助它的ModelConvention来实现。

ModelConvention

ModelConvention定义了操作模型的入口,又或者说是一种契约,通过它我们可以对模型进行修改,常用的Convention包括:

  • IApplicationModelConvention

  • IControllerModelConvention

  • IActionModelConvention

  • IParameterModelConvention

  • IPageRouteModelConvention

这些接口提供了一个共同的方法Apply,方法参数是各自的应用程序模型,以IControllerModelConvention为例看一下它的定义:

namespace Microsoft.AspNetCore.Mvc.ApplicationModels
{//// 摘要://     Allows customization of the Microsoft.AspNetCore.Mvc.ApplicationModels.ControllerModel.//// 言论://     To use this interface, create an System.Attribute class which implements the//     interface and place it on a controller class. Microsoft.AspNetCore.Mvc.ApplicationModels.IControllerModelConvention//     customizations run after Microsoft.AspNetCore.Mvc.ApplicationModels.IApplicationModelConvention//     customizations and before Microsoft.AspNetCore.Mvc.ApplicationModels.IActionModelConvention//     customizations.public interface IControllerModelConvention{//// 摘要://     Called to apply the convention to the Microsoft.AspNetCore.Mvc.ApplicationModels.ControllerModel.//// 参数://   controller://     The Microsoft.AspNetCore.Mvc.ApplicationModels.ControllerModel.void Apply(ControllerModel controller);}
}

从接口摘要可以看到,这个接口允许自定义ControllerModel对象,而如何自定义内容正是通过Apply方法来实现,这个方法提供了当前ControllerModel对象的实例,我们可以在它身上获取到的东西实在太多了,看看它包含些什么:

有了这些,我们可以做很多很灵活的操作,例如通过设置ControllerName字段强制更改控制器的名称让程序中写死的控制器名失效,也可以通过Filters字段动态更新它的过滤器集合,通过RouteValues来更改路由规则等等。

说到这里,很多人会觉得这玩意儿和自定义过滤器看起来差不多,最开始我也这么认为,但经过实际代码调试我发现它的生命周期要比过滤器早的多,或者说根本无法比较,这个家伙只需要在应用启动时执行一次并不用随着每次请求而执行。也就是说,它的执行时间比激活控制器还要早,那时候根本没有过滤器什么事儿,它的调用是发生在app.UseEndpoints()

回到最开始的需求。基于上面的介绍,我们可以自定义如下的约定:

    public class ApiControllerAuthorizeConvention : IControllerModelConvention{public void Apply(ControllerModel controller){if (controller.Filters.Any(x => x is ApiControllerAttribute) && !controller.Filters.Any(x => x is AccessControlFilter)){controller.Filters.Add(new AccessControlAttribute());}}}

上面的主要思路就是通过判断控制器本身的过滤器集合是否包含ApiControllerAttribute来识别是否API Controller,如果是API Controller并且没有标记过AccessControlAttribute的话就新建一个实例加入进去。

那么如何把这个约定注册到应用中呢?在Microsoft.AspNetCore.Mvc.MvcOptions中提供了Conventions属性:

        //// 摘要://     Gets a list of Microsoft.AspNetCore.Mvc.ApplicationModels.IApplicationModelConvention//     instances that will be applied to the Microsoft.AspNetCore.Mvc.ApplicationModels.ApplicationModel//     when discovering actions.public IList<IApplicationModelConvention> Conventions { get; }

通过操作它就能把自定义约定注入进去:

         services.AddMvc(options =>{options.Conventions.Add(new ApiControllerAuthorizeConvention());})

细心的人会发现,Conventions是一个IApplicationModelConvention类型的集合,而我们自定义的Convention是一个IControllerModelConvention,正常来说应该会报错才对?原因是Asp.Net Core的DI框架帮我们提供了一系列扩展方法来简化Convention的添加不用自己再去转换:

通过代码调试发现,应用启动时遍历了系统中的所有控制器去执行Apply操作,那么通过IApplicationModelConvention一样也能实现这个功能,因为它里面包含了控制器集合:

    public class ApiControllerAuthorizeConvention : IApplicationModelConvention{public void Apply(ApplicationModel application){foreach (var controller in application.Controllers){if (controller.Filters.Any(x => x is ApiControllerAttribute) && !controller.Filters.Any(x => x is AccessControlFilter)){controller.Filters.Add(new AccessControlFilter());}}}}

再改进一下

实际开发中我的AccessControlFilter需要通过构造函数注入业务接口,类似于这样:

    public class AccessControlFilter : IActionFilter{private IUserService _userService;public AccessControlFilter(IUserService service){_userService = service;}public void OnActionExecuting(ActionExecutingContext context){//模拟一下业务操作//var user=_userService.GetById(996);//.......}public void OnActionExecuted(ActionExecutedContext context){}}

如何优雅的在Convention中使用DI自动注入呢?Asp.Net Core MVC框架提供的ServiceFilter可以解决这个问题,ServiceFilter本身是一个过滤器,它的不同之处在于能够通过构造函数接收一个Type类型的参数,我们可以在这里把真正要用的过滤器传进去,于是上面的过滤器注册过程演变为:

    controller.Filters.Add(new ServiceFilterAttribute(typeof(AccessControlFilter)));

当然了,要从DI中获取这个filter实例,必须要把它注入到DI容器中:

    services.AddScoped<AccessControlFilter>();

至此,大功告成,继续愉快的CRUD。

突然想起来我上篇文章提到的扩展DI属性注入功能估计也能通过这个玩意实现,eeeeeee...有空了试一下。

总结

总体来说,我通过曲线救国的方式实现了全局过滤器隔离,虽然去遍历目标控制器再手动添加Filter的方式没有那种一行代码就能实现的方式优雅,但我大体来说还算满意,是目前能想到的最好办法。我估摸着,options.Filters.Add(xxx)也是在框架某个时候一个个把xxx丢给各自主人的,瞎猜的,说错不负责

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

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

相关文章

2 未匹配到任何借口_拼多多【关键词精确匹配溢价】给你想要的精准流量,让你订单暴增的秘诀...

关键词匹配方式升级啦&#xff0c;开启精确匹配溢价功能&#xff0c;拥有更多精准流量。为帮助商家解决在使用多多搜索时&#xff0c;遇到的关键词流量不精准、流量不可控、点击率低的问题&#xff0c;多多搜索新推出【关键词精确匹配溢价】功能。通过精确匹配溢价功能&#xf…

如何运用领域驱动设计 - 领域服务

概述本文将介绍领域驱动设计&#xff08;DDD&#xff09;战术模式中另一个非常重要的概念 - 领域服务。在前面两篇博文中&#xff0c;我们已经学习到了什么是值对象和实体&#xff0c;并且能够比较清晰的定位它们自身的行为。但是在某些时候&#xff0c;你会发现某一些业务行为…

指令打印与驱动打印随笔

本文对指令打印和驱动打印做了一个简要的介绍&#xff0c;分享了在开发客户端打印组件时的一些过程并提出了一个新轮子用于解决老的问题并引出更多的新问题。全文大概 3500 字无图&#xff0c;阅读大概需要 7 分钟。驱动打印是指&#xff1a;使用 PrintDocument 进行打印。通过…

er图转为数据流程图_「数据架构」实体关系模型介绍

实体-关系模型(或ER模型)描述特定知识领域中相关的事物。基本的ER模型由实体类型(对感兴趣的事物进行分类)和指定实体之间可能存在的关系(那些实体类型的实例)组成。在软件工程中&#xff0c;为了执行业务流程&#xff0c;ER模型通常用于表示业务需要记住的内容。因此&#xff…

WeihanLi.Npoi 1.7.0 更新介绍

WeihanLi.Npoi 1.7.0 更新介绍Intro昨天晚上发布了 WeihanLi.Npoi 1.7.0 版本&#xff0c;增加了 ColumnInputFormatter/ ColumnOutputFormatter&#xff0c;又进一步增强了导入导出的灵活性&#xff0c;来看下面的示例ColumnInputFormatter/ColumnOutputFormatter示例 Model:i…

【复杂系统迁移 .NET Core平台系列】之迁移项目工程

源宝导读&#xff1a;微软跨平台技术框架—.NET Core已经日趋成熟&#xff0c;已经具备了支撑大型系统稳定运行的条件。本文将介绍明源云ERP平台从.NET Framework向.NET Core迁移过程中的实践经验。一、背景随着ERP的产品线越来越多&#xff0c;业务关联也日益复杂&#xff0c;…

分析股票大数据_Python大数据分析量学祖师爷网站数据

本文通过Python抓取股海明灯涨停预报数据进行分析&#xff0c;股海明灯网站涨停预报数据跟踪功能是需要VIP权限&#xff0c;但这个权限分析数据的功能有限&#xff0c;我们抓取数据后丰富相关功能。一、点击涨停预报后打开以下页面。通过python程序将数据抓取到后台数据库&…

【复杂系统迁移 .NET Core平台系列】之界面层

源宝导读&#xff1a;微软跨平台技术框架—.NET Core已经日趋成熟&#xff0c;已经具备了支撑大型系统稳定运行的条件。本文将介绍明源云ERP平台从.NET Framework向.NET Core迁移过程中的实践经验。一、背景随着ERP的产品线越来越多&#xff0c;业务关联也日益复杂&#xff0c;…

.NET Core MVC扩展实践

源宝导读&#xff1a;明源云ERP的底层架构正在向.Net Core跨平台迁移&#xff0c;我们在过程中遇到了部分不兼容的问题。本文将介绍技术团队如何解决.Net Core与已有MVC框架不兼容问题的解决方案。一、背景云ERP的建模平台是基于.NET Framework构建的&#xff0c;在向.NET Core…

matlab title多个标题_MATLAB中的直方图处理及均衡化

直方图是多种空间域处理技术的基础。仿图操作能有效地用于图像增强&#xff0c;直方图固有的信息在其他图像处理应用中也是非常有用的&#xff0c;如图像压缩与分割。訪图在软件中易于计算&#xff0c;也适用于商用硬件设备&#xff0c;因此直方图成为实时图像处理的一个流行工…

成本计算引擎动态规则解析技术详解

源宝导读&#xff1a;随着企业数字系统应用的越来越深入&#xff0c;业务计算方式也变的越来越复杂&#xff0c;灵活度要求也越来越高。本文将介绍通过将配置动态转换成可执行代码的方式&#xff0c;解决业务计算高度灵活化配置的技术方案。一、背景ERP本质上是一种“业务密集型…

Kubernetes,多云和低代码数据科学:2020年最热门的数据管理趋势

新兴技术为我们的数据之旅铺平了道路。我们已经看到Kubernetes在应用程序自动化方面处于领先地位&#xff0c;越来越多的公司将赌注押在了云上&#xff0c;以及当今的企业对数据科学的依赖程度正不断提&#xff0c;再加上对大数据的人工智能高级分析&#xff0c;可以看到数据管…

matlab光盘映像文件可以删除吗_DVD-Cloner 2020 for mac(DVD光盘刻录工具) 7.00.715

DVD-Cloner Gold 2020版是功能强大的DVD光盘刻录工具&#xff0c;DVD-Cloner Gold 2020版可以轻松刻录光盘以及蓝光光盘&#xff0c;用户可以将任何的文件刻录到DVD光盘中&#xff0c;并可以制作为蓝光光盘&#xff0c;可以很方便地录入视频到光盘中进行保存&#xff0c;刻录好…

性能优化 = 改改代码?

大家好&#xff0c;我是Z哥。好久没写技术文章了&#xff0c;最近正好有进行一些思考&#xff0c;顺手写出来分享给大家。如果不是程序员的话&#xff0c;可以快速扫一眼正文的几个小标题&#xff0c;快速略过即可&#xff0c;毕竟思路和专业无关&#xff0c;很多是相通的。&am…

使用refs获取节点_闲庭信步聊前端 - 原来你是这样的Refs

一、refs 的由来什么是refsrefs是拿到真实的DOM节点和React元素实例的一种方法。在React官方文档中有提到Refs 提供了一种方式&#xff0c;允许我们访问 DOM 节点或在 render 方法中创建的 React 元素。 React是单向的数据流&#xff0c;父子组件的交互是通过props。修改子组件…

从TimeSpan说起

小编在编写WPF程序时&#xff0c;需要做一个判断&#xff1a;定时使用Modbus协议使用Quartz.net 定时任务读取设备中的数据&#xff0c;同时也使用定时任务判断是否长时间获取不到数据的情况&#xff0c;如果程序中超过一分钟没有获取到数据&#xff08;数据没有更新&#xff0…

如何维持手机电池寿命_延长手机电池寿命终极技巧教学,iPhone和安卓手机皆适合...

每隔一阵子就开始有不少用户询问&#xff0c;iPhone电池健康度又剩下多少了&#xff0c;怎么朋友的还维持在100%&#xff0c;是不是我手机电池出问题&#xff0c;引起不少用户翻白眼。会有电池健康度&#xff0c;最主要是要让大家了解目前手机电池当前寿命&#xff0c;只要电池…

2020年了,再不会Https就老了

合格的web后端程序员&#xff0c;除搬砖技能&#xff0c;还必须会给各种web服务器启用Https&#xff0c;本文结合ASP.NET Core部署模型聊一聊启用Https的方式。温故知新目前常见的Http请求明文传输&#xff0c;请求可能被篡改&#xff0c;访问的站点可能被伪造。HTTPS是HTTP加上…

c语言枚举类型例题_[开源资讯]Zig 0.6.0 发布,想要挑战 C 语言

Zig 0.6.0 已发布&#xff0c;这是一门通用编程语言&#xff0c;专为稳定性、可维护性和性能而设计&#xff0c;追求替代 C 语言在系统编程上的最佳地位。Zig 具有以下值得关注的特性&#xff1a;手动管理内存与 C 语言竞争而非依赖它&#xff0c;Zig 标准库不依赖于 libc轻量而…

【实战 Ids4】║ 给授权服务器加个锁——HTTPS配置

在上篇文章《【实战 Ids4】║客户端、服务端、授权中心全线打通&#xff01;》中&#xff0c;我们正式的将三站打通&#xff0c;发布过后&#xff0c;有小伙伴反馈&#xff0c;可能Nginx对配置HTTPS安全协议有点儿问题&#xff0c;我也就半夜趁着没人打扰&#xff0c;疯狂的研究…