ASP.NET Core中间件初始化的实现(2)

/// <summary> /// 将中间件委托添加到应用程序的请求管道。 /// </summary> /// <param>中间件委托</param> /// <returns>The <see cref="IApplicationBuilder"/>.</returns> IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware);

IApplicationBuilder接口里只有Use的方式可以添加中间件,由此我们可以大致猜到两点信息

其它添加中间件的方式,都是在扩展自IApplicationBuilder,并不是IApplicationBuilder本身的方法。

其它添加中间件的形式,最终都会转换为Use的方式。

Use扩展方法

上面我们看到了IApplicationBuilder只包含了一个Use方法,但是我们日常编程中最常使用到的却并不是这一个,而是来自UseExtensions扩展类的Use扩展方法,实现如下所示[]

public static IApplicationBuilder Use(this IApplicationBuilder app, Func<HttpContext, Func<Task>, Task> middleware) { //将middleware转换为Use(Func<RequestDelegate, RequestDelegate> middleware)的形式 return app.Use(next => { return context => { Func<Task> simpleNext = () => next(context); return middleware(context, simpleNext); }; }); }

如预料的那样,Use的扩展方法最终都会转换为Use(Func<RequestDelegate, RequestDelegate> middleware)的形式去执行。Use扩展方法的形式还是比较清晰的,毕竟也是基于委托的形式,而且参数是固定的。

UseMiddleware

上面我们看到了Use的扩展方法,它最终还是转换为Use(Func<RequestDelegate, RequestDelegate> middleware)的形式去执行。接下来我们来看下通过编写类的形式定义中间件会是怎样的转换操作。找到UseMiddleware扩展方法所在的地方,也就是UseMiddlewareExtensions扩展类里[点击查看源码👈],我们最常用的是UseMiddleware这个方法,而且这个方法是UseMiddlewareExtensions扩展类的入口方法[],说白了就是它是完全调用别的方法没有自己的实现逻辑

/// <summary> /// 将中间件类型添加到应用程序的请求管道. /// </summary> /// <typeparam>中间件类型</typeparam> /// <param>传递给中间件类型实例的构造函数的参数.</param> /// <returns>The <see cref="IApplicationBuilder"/> instance.</returns> public static IApplicationBuilder UseMiddleware<[DynamicallyAccessedMembers(MiddlewareAccessibility)]TMiddleware>(this IApplicationBuilder app, params object[] args) { return app.UseMiddleware(typeof(TMiddleware), args); }

继续向下看找到它调用的扩展方法,在展示该方法之前我们先罗列一下该类的常量属性,因为类中的方法有用到,如下所示

internal const string InvokeMethodName = "Invoke"; internal const string InvokeAsyncMethodName = "InvokeAsync";

从这里我们可以得到一个信息,基于约定的形式自定义的中间件触发方法名可以是Invoke或InvokeAsync

继续看执行方法的实现代码

public static IApplicationBuilder UseMiddleware(this IApplicationBuilder app, [DynamicallyAccessedMembers(MiddlewareAccessibility)] Type middleware, params object[] args) { //判断自定义的中间件是否是实现了IMiddleware接口 if (typeof(IMiddleware).GetTypeInfo().IsAssignableFrom(middleware.GetTypeInfo())) { //Middleware不支持直接传递参数 //因为它是注册到容器中的,所以不能通过构造函数传递自定义的参数,否则抛出异常 if (args.Length > 0) { throw new NotSupportedException(Resources.FormatException_UseMiddlewareExplicitArgumentsNotSupported(typeof(IMiddleware))); } //实现IMiddleware接口的中间件走的是这个逻辑,咱们待会看 return UseMiddlewareInterface(app, middleware); } var applicationServices = app.ApplicationServices; return app.Use(next => { //获取自定义中间件类的非静态public方法 var methods = middleware.GetMethods(BindingFlags.Instance | BindingFlags.Public); //查找方法名为Invoke或InvokeAsync的方法 var invokeMethods = methods.Where(m => string.Equals(m.Name, InvokeMethodName, StringComparison.Ordinal) || string.Equals(m.Name, InvokeAsyncMethodName, StringComparison.Ordinal) ).ToArray(); //方法名为Invoke或InvokeAsync的方法只能有有一个,存在多个话会抛出异常 if (invokeMethods.Length > 1) { throw new InvalidOperationException(Resources.FormatException_UseMiddleMutlipleInvokes(InvokeMethodName, InvokeAsyncMethodName)); } //自定义的中间件类中必须包含名为Invoke或InvokeAsync的方法,否则也会抛出异常 if (invokeMethods.Length == 0) { throw new InvalidOperationException(Resources.FormatException_UseMiddlewareNoInvokeMethod(InvokeMethodName, InvokeAsyncMethodName, middleware)); } //名为Invoke或InvokeAsync的方法的返回值类型必须是Task类型,否则会抛出异常 var methodInfo = invokeMethods[0]; if (!typeof(Task).IsAssignableFrom(methodInfo.ReturnType)) { throw new InvalidOperationException(Resources.FormatException_UseMiddlewareNonTaskReturnType(InvokeMethodName, InvokeAsyncMethodName, nameof(Task))); } //获取Invoke或InvokeAsync方法的参数 var parameters = methodInfo.GetParameters(); //如果该方法不存在参数或方法的第一个参数不是HttpContext类型的实例,会抛出异常 if (parameters.Length == 0 || parameters[0].ParameterType != typeof(HttpContext)) { throw new InvalidOperationException(Resources.FormatException_UseMiddlewareNoParameters(InvokeMethodName, InvokeAsyncMethodName, nameof(HttpContext))); } //定义新的数组比传递的参数长度多一个,为啥呢?往下看。 var ctorArgs = new object[args.Length + 1]; //因为方法数组的首元素是RequestDelegate类型的next //也就是基于约定定义的中间件构造函数的第一个参数是RequestDelegate类型的实例 ctorArgs[0] = next; Array.Copy(args, 0, ctorArgs, 1, args.Length); //创建基于约定的中间件实例 //又看到ActivatorUtilities这个类了,关于这个类有兴趣的可以研究一下,可以根据容器创建类型实例,非常好用 var instance = ActivatorUtilities.CreateInstance(app.ApplicationServices, middleware, ctorArgs); //如果Invoke或InvokeAsync方法只有一个参数,则直接创建RequestDelegate委托返回 if (parameters.Length == 1) { //RequestDelegate其实就是public delegate Task RequestDelegate(HttpContext context); return (RequestDelegate)methodInfo.CreateDelegate(typeof(RequestDelegate), instance); } //编译Invoke或InvokeAsync方法,关于Compile的实现等会咱们再看 var factory = Compile<object>(methodInfo, parameters); //返回这个委托 //看着这个委托的格式有点眼熟,其实就是RequestDelegate即public delegate Task RequestDelegate(HttpContext context); return context => { var serviceProvider = context.RequestServices ?? applicationServices; //serviceProvider不能为空,否则没法玩了 if (serviceProvider == null) { throw new InvalidOperationException(Resources.FormatException_UseMiddlewareIServiceProviderNotAvailable(nameof(IServiceProvider))); } //返回委托执行结果 return factory(instance, context, serviceProvider); }; }); }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyfdwd.html