当前位置: 首页 > news >正文

建企业网站 硬件网站建设 淘宝运营

建企业网站 硬件,网站建设 淘宝运营,北京seo培训,东莞网站设计公司淘宝前言本文编写时源码参考github仓库主分支。aspnetcore提供了Use方法供开发者自定义中间件#xff0c;该方法接收一个委托对象#xff0c;该委托接收一个RequestDelegate对象#xff0c;并返回一个RequestDelegate对象#xff0c;方法定义如下#xff1a;IApplicationBuild… 前言本文编写时源码参考github仓库主分支。aspnetcore提供了Use方法供开发者自定义中间件该方法接收一个委托对象该委托接收一个RequestDelegate对象并返回一个RequestDelegate对象方法定义如下IApplicationBuilder Use(FuncRequestDelegate, RequestDelegate middleware);委托RequestDelegate的定义/// summary /// A function that can process an HTTP request. /// /summary /// param namecontextThe see crefHttpContext/ for the request./param /// returnsA task that represents the completion of request processing./returns public delegate Task RequestDelegate(HttpContext context);如果我们直接使用IApplicationBuilder.Use来写中间件逻辑可以使用lamda表达式来简化代码如下app.Use((RequestDelegate next)  {return (HttpContext ctx) {// do your logicreturn next(ctx);}; });如果写一些简单的逻辑这种方式最为方便问题是如果需要写的中间件代码比较多依然这样去写会导致我们Program.cs文件代码非常多如果有多个中间件那么最后我们的的Program.cs文件包含多个中间件代码看上去十分混乱。将中间件逻辑独立出来为了解决我们上面的代码不优雅我们希望能将每个中间件业务独立成一个文件多个中间件代码不混乱的搞到一起。我们需要这样做。单独的中间件文件// Middleware1.cs public class Middleware1 {public static RequestDelegate Logic(RequestDelegate requestDelegate){return (HttpContext ctx) {// do your logicreturn requestDelegate(ctx);};} }调用中间件app.Use(Middleware1.Logic); // 以下是其他中间件示例 app.Use(Middleware2.Logic); app.Use(Middleware3.Logic); app.Use(Middleware4.Logic);这种方式可以很好的将各个中间件逻辑独立出来Program.cs此时变得十分简洁然而我们还不满足这样因为我们的Logic方法中直接返回一个lamada表达式RequestDelegate对象代码层级深了一层每个中间件都多写这一层壳似乎不太优雅能不能去掉这层lamada表达式呢UseMiddlewareExtensions为了解决上面提到的痛点UseMiddlewareExtensions扩展类应运而生它在Aspnetcore底层大量使用,它主要提供一个泛型UseMiddlewareT方法用来方便我们注册中间件下面是该方法的定义public static IApplicationBuilder UseMiddlewareTMiddleware(this IApplicationBuilder app, params object?[] args)如果只看这个方法的声明估计没人知道如何使用因为该方法接收的泛型参数TMiddleware没有添加任何限制而另一个args参数也是object类型而且是可以不传的也就是它只需要传任意一个类型都不会在编译时报错。 比如这样完全不会报错当然如果你这样就运行程序一定会收到下面的异常System.InvalidOperationException:“No public Invoke or InvokeAsync method found for middleware of type System.String.”提示我们传的类型没有Invoke或InvokeAsync公共方法这里大概能猜到底层应该是通过反射进行动态调用Invoke或InvokeAsync公共方法的。源码分析想要知道其本质唯有查看源码,以下源码来自UseMiddlewareExtensions如下该扩展类一共提供两个并且是重载的公共方法UseMiddleware一般都只会使用第一个UseMiddleware,第一个UseMiddleware方法内部再去调用第二个UseMiddleware方法源码中对类型前面添加的[DynamicallyAccessedMembers(MiddlewareAccessibility)]属性可以忽略它的作用是为了告诉编译器我们通过反射访问的范围以防止对程序集对我们可能调用的方法或属性等进行裁剪。internal const string InvokeMethodName  Invoke; internal const string InvokeAsyncMethodName  InvokeAsync;/// summary /// Adds a middleware type to the applications request pipeline. /// /summary /// typeparam nameTMiddlewareThe middleware type./typeparam /// param nameappThe see crefIApplicationBuilder/ instance./param /// param nameargsThe arguments to pass to the middleware type instances constructor./param /// returnsThe see crefIApplicationBuilder/ instance./returns public static IApplicationBuilder UseMiddleware[DynamicallyAccessedMembers(MiddlewareAccessibility)] TMiddleware(this IApplicationBuilder app, params object?[] args) {return app.UseMiddleware(typeof(TMiddleware), args); }/// summary /// Adds a middleware type to the applications request pipeline. /// /summary /// param nameappThe see crefIApplicationBuilder/ instance./param /// param namemiddlewareThe middleware type./param /// param nameargsThe arguments to pass to the middleware type instances constructor./param /// returnsThe see crefIApplicationBuilder/ instance./returns public static IApplicationBuilder UseMiddleware(this IApplicationBuilder app,[DynamicallyAccessedMembers(MiddlewareAccessibility)] Type middleware,params object?[] args) {if (typeof(IMiddleware).IsAssignableFrom(middleware)){// IMiddleware doesnt support passing args directly since its// activated from the containerif (args.Length  0){throw new NotSupportedException(Resources.FormatException_UseMiddlewareExplicitArgumentsNotSupported(typeof(IMiddleware)));}return UseMiddlewareInterface(app, middleware);}var applicationServices  app.ApplicationServices;var methods  middleware.GetMethods(BindingFlags.Instance | BindingFlags.Public);MethodInfo? invokeMethod  null;foreach (var method in methods){if (string.Equals(method.Name, InvokeMethodName, StringComparison.Ordinal) || string.Equals(method.Name, InvokeAsyncMethodName, StringComparison.Ordinal)){if (invokeMethod is not null){throw new InvalidOperationException(Resources.FormatException_UseMiddleMutlipleInvokes(InvokeMethodName, InvokeAsyncMethodName));}invokeMethod  method;}}if (invokeMethod is null){throw new InvalidOperationException(Resources.FormatException_UseMiddlewareNoInvokeMethod(InvokeMethodName, InvokeAsyncMethodName, middleware));}if (!typeof(Task).IsAssignableFrom(invokeMethod.ReturnType)){throw new InvalidOperationException(Resources.FormatException_UseMiddlewareNonTaskReturnType(InvokeMethodName, InvokeAsyncMethodName, nameof(Task)));}var parameters  invokeMethod.GetParameters();if (parameters.Length  0 || parameters[0].ParameterType ! typeof(HttpContext)){throw new InvalidOperationException(Resources.FormatException_UseMiddlewareNoParameters(InvokeMethodName, InvokeAsyncMethodName, nameof(HttpContext)));}var state  new InvokeMiddlewareState(middleware);return app.Use(next {var middleware  state.Middleware;var ctorArgs  new object[args.Length  1];ctorArgs[0]  next;Array.Copy(args, 0, ctorArgs, 1, args.Length);var instance  ActivatorUtilities.CreateInstance(app.ApplicationServices, middleware, ctorArgs);if (parameters.Length  1){return (RequestDelegate)invokeMethod.CreateDelegate(typeof(RequestDelegate), instance);}var factory  Compileobject(invokeMethod, parameters);return context {var serviceProvider  context.RequestServices ?? applicationServices;if (serviceProvider  null){throw new InvalidOperationException(Resources.FormatException_UseMiddlewareIServiceProviderNotAvailable(nameof(IServiceProvider)));}return factory(instance, context, serviceProvider);};}); }第一个UseMiddleware可以直接跳过看第二个UseMiddleware方法该方法一上来就先判断我们传的泛型类型是不是IMiddleware接口的派生类如果是直接交给UseMiddlewareInterface方法。if (typeof(IMiddleware).IsAssignableFrom(middleware)){// IMiddleware doesnt support passing args directly since its// activated from the containerif (args.Length  0){throw new NotSupportedException(Resources.FormatException_UseMiddlewareExplicitArgumentsNotSupported(typeof(IMiddleware)));}return UseMiddlewareInterface(app, middleware);}这里总算看到应该有的东西了如果声明UseMiddlewareT方法时对泛型T添加IMiddleware限制,我们不看源码就知道如何编写我们的中间件逻辑了只需要写一个类继承IMiddleware并实现InvokeAsync方法即可 UseMiddlewareInterface方法的实现比较简单因为我们继承了接口逻辑相对会简单点。private static IApplicationBuilder UseMiddlewareInterface(IApplicationBuilder app,Type middlewareType) {return app.Use(next {return async context {var middlewareFactory  (IMiddlewareFactory?)context.RequestServices.GetService(typeof(IMiddlewareFactory));if (middlewareFactory  null){// No middleware factorythrow new InvalidOperationException(Resources.FormatException_UseMiddlewareNoMiddlewareFactory(typeof(IMiddlewareFactory)));}var middleware  middlewareFactory.Create(middlewareType);if (middleware  null){// The factory returned null, its a broken implementationthrow new InvalidOperationException(Resources.FormatException_UseMiddlewareUnableToCreateMiddleware(middlewareFactory.GetType(), middlewareType));}try{await middleware.InvokeAsync(context, next);}finally{middlewareFactory.Release(middleware);}};}); }public interface IMiddleware {/// summary/// Request handling method./// /summary/// param namecontextThe see crefHttpContext/ for the current request./param/// param namenextThe delegate representing the remaining middleware in the request pipeline./param/// returnsA see crefTask/ that represents the execution of this middleware./returnsTask InvokeAsync(HttpContext context, RequestDelegate next); }如果我们的类不满足IMiddleware继续往下看通过反射查找泛型类中Invoke或InvokeAsync方法var applicationServices  app.ApplicationServices; var methods  middleware.GetMethods(BindingFlags.Instance | BindingFlags.Public); MethodInfo? invokeMethod  null; foreach (var method in methods) {if (string.Equals(method.Name, InvokeMethodName, StringComparison.Ordinal) || string.Equals(method.Name, InvokeAsyncMethodName, StringComparison.Ordinal)){// 如果Invoke和InvokeAsync同时存在则抛出异常也就是我们只能二选一if (invokeMethod is not null){throw new InvalidOperationException(Resources.FormatException_UseMiddleMutlipleInvokes(InvokeMethodName, InvokeAsyncMethodName));}invokeMethod  method;} }// 如果找不到Invoke和InvokeAsync则抛出异常上文提到的那个异常。 if (invokeMethod is null) {throw new InvalidOperationException(Resources.FormatException_UseMiddlewareNoInvokeMethod(InvokeMethodName, InvokeAsyncMethodName, middleware)); }// 如果Invoke和InvokeAsync方法的返回值不是Task或Task的派生类则抛出异常 if (!typeof(Task).IsAssignableFrom(invokeMethod.ReturnType)) {throw new InvalidOperationException(Resources.FormatException_UseMiddlewareNonTaskReturnType(InvokeMethodName, InvokeAsyncMethodName, nameof(Task))); } Snippet// 如果Invoke和InvokeAsync方法没有参数或第一个参数不是HttpContext抛异常 var parameters  invokeMethod.GetParameters(); if (parameters.Length  0 || parameters[0].ParameterType ! typeof(HttpContext)) {throw new InvalidOperationException(Resources.FormatException_UseMiddlewareNoParameters(InvokeMethodName, InvokeAsyncMethodName, nameof(HttpContext))); }上面一堆逻辑主要就是检查我们的Invoke和InvokeAsync方法是否符合要求,即必须是接收HttpContext参数返回Task对象这恰好就是委托RequestDelegate的定义。构造RequestDelegate这部分源码的解读都注释到相应的位置了如下var state  new InvokeMiddlewareState(middleware); // 调用Use函数向管道中注册中间件 return app.Use(next  {var middleware  state.Middleware;var ctorArgs  new object[args.Length  1];// next是RequestDelegate对象作为构造函数的第一个参数传入ctorArgs[0]  next;Array.Copy(args, 0, ctorArgs, 1, args.Length);// 反射实例化我们传入的泛型类并把next和args作为构造函数的参数传入var instance  ActivatorUtilities.CreateInstance(app.ApplicationServices, middleware, ctorArgs);// 如果我们的Invoke方法只有一个参数则直接创建该方法的委托if (parameters.Length  1){return (RequestDelegate)invokeMethod.CreateDelegate(typeof(RequestDelegate), instance);}// 当Invoke方法不止一个参数HttpContext通过Compile函数创建动态表达式目录树// 表达式目录树的构造此处略过其目的是实现将除第一个参数的其他参数通过IOC注入var factory  Compileobject(invokeMethod, parameters);return context {// 获取serviceProvider用于在上面构造的表达式目录树中实现依赖注入var serviceProvider  context.RequestServices ?? applicationServices;if (serviceProvider  null){throw new InvalidOperationException(Resources.FormatException_UseMiddlewareIServiceProviderNotAvailable(nameof(IServiceProvider)));}// 将所需的参数传入构造的表达式目录树工厂return factory(instance, context, serviceProvider);}; });至此整个扩展类的源码就解读完了。通过UseMiddleware注入自定义中间件通过上面的源码解读我们知道了其实我们传入的泛型类型是有严格的要求的主要有两种通过继承IMiddleware继承IMiddleware并实现该接口的InvokeAsync函数public class Middleware1 : IMiddleware {public async Task InvokeAsync(HttpContext context, RequestDelegate next){// do your logicawait next(context);} }通过反射我们知道在不继承IMiddleware的情况下底层会通过反射实例化泛型类型并通过构造函数传入RequestDelegate,而且要有一个公共函数Invoke或InvokeAsync并且接收的第一个参数是HttpContext返回Task,根据要求我们将Middleware1.cs改造如下public class Middleware1 {RequestDelegate next;public Middleware1(RequestDelegate next){this.next  next;}public async Task Invoke(HttpContext httpContext){// do your logicawait this.next(httpContext);} }总结通过源码的学习我们弄清楚底层注册中间件的来龙去脉两种方式根据自己习惯进行使用笔者认为通过接口的方式更加简洁直观简单并且省去了反射带来的性能损失推荐使用。既然通过继承接口那么爽为啥还费那么大劲实现反射的方式呢由源码可知如果继承接口的话就不能进行动态传参了。if (typeof(IMiddleware).IsAssignableFrom(middleware)){// IMiddleware doesnt support passing args directly since its// activated from the containerif (args.Length  0){throw new NotSupportedException(Resources.FormatException_UseMiddlewareExplicitArgumentsNotSupported(typeof(IMiddleware)));}return UseMiddlewareInterface(app, middleware);}所以在需要传参的场景则必须使用反射的方式所以两种方式都有其存在的必要。如果本文对您有帮助还请点赞转发关注一波支持作者。
http://www.zqtcl.cn/news/12183/

相关文章:

  • 网站建设图书推荐信息免费发布平台
  • opencms 做的网站wordpress在线制作
  • 保险网站有哪些平台如何查询商标是否已经被注册
  • 什么网站可以做外国生意黄骅怎么样
  • 公司宣传 如何做公司网站现货行情分析软件app
  • 模仿网站属于侵权吗seo怎么做关键词排名
  • 网站建设如何更加稳定seo免费工具
  • 企业网站源码 一品资源网网站建设合同封皮
  • 网站忘了怎么办啊企业网站建设 租用服务器
  • 简单的网站模板ip上海官网
  • 衡阳城乡建设局网站广州有建网站的公司吗
  • 贵阳网站如何推广视频网站开发前景
  • 58同城东莞招聘网最新招聘网站的seo如何优化
  • 接送车服务网站怎么做网络营销模式和电子商务模式是一对紧密相关
  • php网站开发如何赚钱dedecms 网站访问量
  • 珠宝钻石网站建站台州市建设规划局网站6
  • 网站开发经验与教训范文网站开发结构文档
  • 在线学做网站接单做网站的
  • 广告网站设计方案app推广引流渠道
  • 唐山模板建站系统推广公司违法吗
  • 如何做属于自己的网站张家界做网站公司
  • 免费网站建站排行榜廊坊哪里有做网站建设的
  • 网站建设的方法和技术免费活动策划方案的网站
  • 南京市建设工程档案馆网站百度知道合伙人官网
  • 企业固定ip做网站浏览器显示不安全网站建设
  • 做网站以前出名的公司百度推广账户优化
  • 建设企业管理类网站网站的域名
  • 专做影视评论的网站wordpress wp大学
  • 英文网站收录提交wordpress新手主题
  • 阿里巴巴国际站开店流程及费用加工平台苏州纳米所