这批.Net程序员水平不行啊!居然ASP.NET Core Middleware都不会用
最近问了几个面试同一个问题:如果有多个自定义Middleware,如何控制它们的执行顺序(比如先判断用户合法再写访问日志)。居然大部分人答不上来?!
对此,你有什么看法?
ASP.NET Core Middleware的调用顺序
这里我直接贴上官方文档[1]中的图片:
ASP.NET Core 请求管道包含一系列请求委托,依次调用。而调用顺序实际上就是我们在Startup.cs中注册(使用UseMiddlewareExtensions.UseMiddleware方法
)它们的顺序。
示例代码如下:
public void ConfigureServices(IServiceCollection services)
{//注册生命周期services.AddTransient<TransientMiddleware>();services.AddScoped<ScopedMiddleware>();
}public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{//注册调用顺序app.UseMiddleware<TransientMiddleware>();app.UseMiddleware<ScopedMiddleware>();
}
但这种方式,对于调整自定义Middleware的需求,需要经常修改Startup.cs,而且会使代码比较凌乱,可读性较差。
可以使用下面的方式,简化注册代码:
public void ConfigureServices(IServiceCollection services)
{services.AddMiddlewares();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{app.UseMiddlewares();
}
实现方式
1.定义Attribute
MiddlewareRegisterAttribute
将放在每个Middleware实现类上,表明它是需要被注册的Middleware。
[AttributeUsage(AttributeTargets.Class)]
public class MiddlewareRegisterAttribute : Attribute
{//注册顺序public int Sort { get; set; } = int.MaxValue;//生命周期public ServiceLifetime Lifetime { get; set; } = ServiceLifetime.Scoped;
}
2.定义注册信息类
MiddlewareRegisterInfo
用于存放Middleware的注册信息,供注册方法调用。
public class MiddlewareRegisterInfo
{public MiddlewareRegisterInfo(Type type,MiddlewareRegisterAttribute attribute){Type = type;Sort = attribute.Sort;Lifetime = attribute.Lifetime;}public Type Type { get; private set; }public int Sort { get; private set; }public ServiceLifetime Lifetime { get; private set; }
}
2.实现注册扩展方法
读取Assembly中的Type, 如果存在MiddlewareRegisterAttribute
就把它放入List<MiddlewareRegisterInfo>
列表中,最后根据Sort
属性顺序依次注册,代码如下:
public static class MiddlewareRegisterExtensions
{private static readonly IEnumerable<MiddlewareRegisterInfo> _middlewareRegisterInfos = GetMiddlewareRegisterInfos();public static IServiceCollection AddMiddlewares(this IServiceCollection services){foreach (var middlewareRegisterInfo in _middlewareRegisterInfos){switch (middlewareRegisterInfo.Lifetime){case ServiceLifetime.Singleton:services.AddSingleton(middlewareRegisterInfo.Type);break;case ServiceLifetime.Transient:services.AddTransient(middlewareRegisterInfo.Type);break;default:services.AddScoped(middlewareRegisterInfo.Type);break;}}return services;}public static IApplicationBuilder UseMiddlewares(this IApplicationBuilder applicationBuilder){foreach (var middlewareRegisterInfo in _middlewareRegisterInfos){applicationBuilder.UseMiddleware(middlewareRegisterInfo.Type);}return applicationBuilder;}private static List<MiddlewareRegisterInfo> GetMiddlewareRegisterInfos(){var middlewareRegisterInfos = new List<MiddlewareRegisterInfo>();//所有包含Middleware的Assemblyvar assemblies = new Assembly[] { typeof(Startup).Assembly };foreach (var assembly in assemblies){foreach (var type in assembly.GetTypes().Where(x => !x.IsAbstract)){var attribute = type.GetCustomAttribute<MiddlewareRegisterAttribute>();if (attribute != null){middlewareRegisterInfos.Add(new MiddlewareRegisterInfo(type, attribute));}}}return middlewareRegisterInfos.OrderBy(p=>p.Sort).ToList();}
}
测试一下
创建3个Middleware,功能仅仅是输出日志:
[MiddlewareRegister(Sort = 100)]
public class OneMiddleware : IMiddleware
{private readonly ILogger<OneMiddleware> logger;public OneMiddleware(ILogger<OneMiddleware> logger){this.logger = logger;}public async Task InvokeAsync(HttpContext context, RequestDelegate next){logger.LogInformation("One");await next(context);}
}
Sort
用100、200、300,方便后面修改排序。
运行效果如下图:
现在,将ThreeMiddleware的Sort
改为150,调整注册顺序,再次运行,效果如下图:
结论
当然,这个解决方案也存在一些缺点,比如修改排序的位置移到每个Middleware,比较分散。但整体来说,代码更易读!
如果你有其他实现方式,欢迎到公众号后台留言指教。
如果你觉得这篇文章对你有所启发,请关注我的个人公众号”My IO“,记住我!
参考资料
[1]
官方文档: https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/middleware
这批.Net程序员水平不行啊!居然ASP.NET Core Middleware都不会用相关推荐
- 程序员水平分级 你属于哪一类?
程序员水平分级 你属于哪一类? 2012-02-14 16:57 | 14782次阅读 | 来源:whattofix.com [已有69条评论]发表评论 关键词:程序员,编程,评级 | 作者:Dani ...
- 程序员水平自测题:程序员们,想知道你的技术达到了什么水平吗?
程序员甲抱怨:"干IT太苦了,数据是越存越多,预算是越来越少,好基友是越来越多,女朋友是越来越少.想换一行怎么办??" 程序员乙:"敲一下回车." 中国的程序员 ...
- 【Rust 日报】2021-07-04 如何在面试中确定 Rust 程序员水平?
如何在面试中确定 Rust 程序员水平? 对于这个问题,张汉东老师在 RustFriday 飞书群线上沙龙第十三期中进行了分享: 视频:RustFriday 飞书群线上沙龙 第十三期 | [讨论]如何 ...
- 34岁程序员面试被拒:混得好的年轻人都有这3个特质
34岁程序员面试被拒:混得好的年轻人都有这3个特质 前几天我参加了一场闭门创业营,很多大佬分享了很多干货和经验,但是最打动我的,还是其中一位前辈分享的故事--"如何判断一个员工是否有潜力&q ...
- Android架构师吐槽腾讯王者荣耀的程序员,排位匹配算法怎么搞的,每次都输
腾讯王者荣耀的开发来来来出来聊聊,真是日了狗了,多次离上王者还差两三颗星的时候队友就开始水的一塌糊涂,对面就牛逼的不行. 又连跪回去了,被对面把屎都打出来了,实在忍不住来吐槽,你们这个排位匹配算法到底 ...
- 程序员的幸福生活——有你的日子,每天都是情人节
主人公:缘生梦 老婆:华华誓界 2月14日已经过去两天了,这个日子对于很多人来说意义非凡.本来这篇文章打算是这天写的,可是本人有严重的拖延症,被各种事情一耽误就给拖到了第二天,想就这样算了吧,七夕的时 ...
- 兄dei,作为程序员的你,这些一直接触的词都念对了吗?
点击蓝色"程序猿DD"关注我哟 加个"星标",不忘签到哦 很多时候,大家可能都觉得程序员英文一定很好.因为我们每天都对着满屏幕的英文,噼里啪啦一整天.讨论个需求 ...
- c语言输出我爱你程序,程序员表白教程,这些代码用过的都成功了!
原标题:程序员表白教程,这些代码用过的都成功了! 作为一名程序员,如何用自己的技术向喜欢的人表白? 这篇程序员表白教程,可以让你创造出不一样的浪漫! 你值得拥有! 1. I Love You Batc ...
- 设计师和程序员必备:全世界最著名的 icon 网站都在这了
设计师和程序员必备:全世界最著名的 icon 网站都在这了 作为一个多年的独立开发者,收藏了非常多免费无版权图片网站.免费 icons.知名的技术人博客.有趣的网站等等,今天给大家分享我这几年收藏的 ...
最新文章
- 【怎样写代码】函数式编程 -- Lambda表达式(三):LINQ初步
- spark读取hdfs路径下的数据_Spark读取HDFS数据分区参考
- Solr分页与高亮(使用SolrNet实现)
- 2020ICPC(小米邀请赛2) - Data Structure Problem(线段树+树状数组)
- 函数平移口诀_初三二次函数平移规律的口诀
- linux动态追踪神器——Strace实例介绍【转】
- 过来人谈在美国大学里的中国研究生
- 计算机旅游网站毕业论文,旅游网站的设计与实现(毕业论文)
- 设计一个具有大纯时延时间的一阶惯性环节的计算机控制系统,一阶惯性环节的计算机控制课程设计【参考】.doc...
- Quartz定时任务框架(一)
- 企业需要关注的零信任 24 问
- android gsm功能,Android手机-GSM网络与WCDMA网络选择的设置
- 桌面点击鼠标右键一直显示转圈卡住如何解决
- JAVA Swing主题 简洁扁平化苹果风格主题
- 一座古老与现代和谐共融的城市
- JAVA基础常见的知识点
- arcgis地图加载离线地图
- CRM销售管理系统能够给企业带来哪些好处?
- 今天,我们这么和霍金说再见
- 题解 - CF662C Binary Table
热门文章
- saltapi java_搭建基于Jenkins salt-api的运维工具
- python函数 global_**Python的函数参数传递 和 global
- spring boot拦截器中获取request post请求中的参数(转)
- (一)使用appium之前为什么要安装nodejs???
- C#构造函数、操作符重载以及自定义类型转换
- 初识Spark2.0之Spark SQL
- hdu-5781 ATM Mechine(dp+概率期望)
- http://www.appinn.com/bookmark-manager-chrome/
- Office SharePoint Server 2007
- ADO.NET Entity Framework学习笔记(2)建模[转]