这批.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

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

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

相关文章

在Heroku上部署(托管)Rails项目

2019独角兽企业重金招聘Python工程师标准>>> ①、安装heroku&#xff1a; &#xff04; gem install heroku ②、先要生成一个公钥&#xff0c;使用命令: $ ssh-keygen -t rsaGenerating public/private rsa key pair. Enter file in which to save the key (/home/…

java关于异常的面试程序题_Java挑战:最难的十个面试题(附答案)「下」

原标题&#xff1a;Java挑战&#xff1a;最难的十个面试题(附答案)「下」版权声明&#xff1a;本文为CSDN博主「华为云」的原创文章&#xff0c;遵循 CC 4.0 BY-SA 版权协议&#xff0c;转载请附上原文出处链接及本声明。原文链接&#xff1a;https://blog.csdn.net/devcloud/a…

数学知识点大集合!有了它学数学真的很简单!

▲ 点击查看很多学生对于数学这门学科都有莫名的恐惧感&#xff0c;不知道怎样学才能学得好。其实&#xff0c;好的方法能让学习效率达到最佳效果。有的时候&#xff0c;孩子学习不好&#xff0c;真的不是因为孩子笨&#xff0c;而是这种方法不适合孩子。其实小学数学学习的难度…

使用 Blazor 开发内部后台(三):登录

James: 《使用Blazor开发内部后台》系列是技术社区中一位朋友投稿的系列文章&#xff0c;介绍自己为公司的 WebForm 遗留系统使用 Blazor 重写前端 UI 的经历。本文为第三篇&#xff0c;如果错过了前两篇&#xff0c;建议先阅读一下&#xff1a;使用 Blazor 开发内部后台&#…

论文排版怕翻车?这个排版神器是时候用起来了!

全世界只有3.14 % 的人关注了青少年数学之旅相信每年临近准备毕设或者毕业论文的同学会遇到这些问题&#xff1a;“我的毕业论文提交一次就被导师批评一次&#xff0c;内容不行就算了&#xff0c;格式也有问题&#xff01;改论文改到绝望”“期刊的版式要求不是统一的&#xff…

.NET Day in China(上海)| 线上线下

点击蓝字关注我们活动简介.NET 6 Preview 6 在 7月14日已经发布&#xff0c;.NET 6 是微软开启全平台统一一个 .NET 计划以来的第一个 LTS 版本&#xff0c;意义重大&#xff0c;微软在 .NET 6 引入了 MAUI&#xff0c;跨平台开发将更为简单&#xff0c;ASP.NET Core 也在不断的…

java综合图形界面程序设计_java综合图形界面程序设计.doc

java综合图形界面程序设计.doc还剩10页未读&#xff0c;继续阅读下载文档到电脑&#xff0c;马上远离加班熬夜&#xff01;亲&#xff0c;喜欢就下载吧&#xff0c;价低环保&#xff01;内容要点&#xff1a;[键入文字]10四、实验小结(包括问题和解决方法、心得体会等)这次课程…

[导入]C++程序随笔

C程序的一些随笔文章来源:http://blog.csdn.net/jaopen/archive/2006/03/13/622822.aspx

你有见过从肚子里抽出来的脂肪吗? | 今日趣图

全世界只有3.14 % 的人关注了青少年数学之旅不在家&#xff1f;快递给你放火烧了科普中国我在偷窥你上网...英式没品笑话学校食堂全新版本的空调苍南派轮世界各国的数学水平天秀bot你永远不知道外卖商家还有什么隐藏“绝活”图片迷惑行為大賞你有见过肚子里抽出来的脂肪吗&…

.NET Day in China(上海-7.24)| 线上线下

点击蓝字关注我们活动简介.NET 6 Preview 6 在 7月14日已经发布&#xff0c;.NET 6 是微软开启全平台统一一个 .NET 计划以来的第一个 LTS 版本&#xff0c;意义重大&#xff0c;微软在 .NET 6 引入了 MAUI&#xff0c;跨平台开发将更为简单&#xff0c;ASP.NET Core 也在不断的…

javasript 面向对象

JavaScript. 是一种解释型的、基于对象的脚本语言。尽管与 C、C# 这样成熟的面向对象的语言相比&#xff0c;JavaScript的功能要弱一些&#xff0c;但对于它的预期用途而言&#xff0c;JavaScript的功能已经足够大了。但是由于各种各样的原因&#xff0c;我们在实际进行开发的过…

砸4亿美元,GE豪赌的全球最大风力发电机到底多大?

全世界只有3.14 % 的人关注了青少年数学之旅叶片长达107米&#xff0c;转子直径为220米&#xff0c;轮毂高度为135米&#xff0c;叶尖最大高度为260米&#xff0c;几乎是纽约自由女神像从地面到火炬尖端高度的三倍。这就是巨头GE豪赌的全球最大风力发电机&#xff1a;Haliade-X…

VisualStudio配置中文提示

开篇语IntelliSense 是一种代码完成辅助工具&#xff0c;可以在不同的集成开发环境 (IDE) 中使用&#xff0c;例如 Visual Studio。默认情况下&#xff0c;在开发 .NET 项目时&#xff0c;SDK 仅包含英语版本的 IntelliSense 文件。虽然推荐使用英文&#xff0c;可以熟悉和学习…

丢失日志文件的风险与对策

实验背景&#xff1a;在备份与恢复数据库时&#xff0c;偶尔使用分离/附加的方法。如果在附加时丢失了或者删除了日志文件&#xff08;LDF&#xff09;&#xff0c;可能会有哪些风险呢&#xff1f;下面通过实验来验证。一、搭建环境1. 创建数据库CREATE DATABASE [db01] ON PR…

A和G cup的差距究竟有多大?| 今日趣图

全世界只有3.14 % 的人关注了青少年数学之旅太阳其实一直在狂奔太阳带着地球等行星以250km/s的速度在绕着银河系公转每转一圈需要2.5亿年图源见水印A罩杯和G罩杯的差距有多大錶情包运动鞋后面的这个东西原来是用来晒鞋子的抖音然一往一捆蛏子上撒盐会发生什么&#xff1f;残酷的…

Javascript函数调用的四种模式

Javascript一共有四种调用模式&#xff1a;方法调用模式、函数调用模式、构造器调用模式以及apply调用模式。调用模式不同&#xff0c;对应的隐藏参数this值也会不同。 函数作为对象的属性时&#xff0c;称为方法。此时函数&#xff08;即方法&#xff09;中的this对应是该对象…

我背着女朋友,用 Python 偷偷抓取了她的行踪

全世界只有3.14 %的人关注了青少年数学之旅1目 标 场 景有时候女朋友一个人在外面玩耍&#xff0c;问她在哪个地方&#xff0c;就是不告诉我。但是&#xff0c;你又很想知道女朋友的「位置」&#xff0c;这该如何是好&#xff1f;其实你可以这样套路女朋友&#xff0c;假装自己…

ASP.NET Core 中的规约模式(Specification Pattern )——增强泛型仓储模式

原文链接&#xff1a;https://codewithmukesh.com/blog/specification-pattern-in-aspnet-core/在本文中&#xff0c;我们将讨论在 ASP.NET Core 应用程序中实现规约模式以及它如何增强现有的泛型仓储模式。我们将从头开始构建具有泛型仓储模式、Entity Framework Core的 ASP.N…

动画演示男性结扎手术 | 今日趣图

全世界只有3.14 % 的人关注了青少年数学之旅流鼻涕了怎么办&#xff1f;医学教育徐琦招聘程序员啦知识萌死大丧失&#xff1b;图熊本科技把下列句子补充完整图三好学生李宇幼年的大象喝水并不会使用鼻子而是趴在水里直接用嘴大喝一顿它们9个月之后才会懂得用鼻子喝水科普斯基请…

AspNetCoreMassTransit Courier实现分布式事务

在之前的一篇博文中&#xff0c;CAP框架可以方便我们实现非实时、异步场景下的最终一致性&#xff0c;而有些用例总是无法避免的需要在实时、同步场景下进行&#xff0c;可以借助Saga事务来解决这一困扰。在一些博文和仓库中也搜寻到了.Net下实现Saga模式的解决方案MassTransit…