最新文章专题视频专题问答1问答10问答100问答1000问答2000关键字专题1关键字专题50关键字专题500关键字专题1500TAG最新视频文章推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37视频文章20视频文章30视频文章40视频文章50视频文章60 视频文章70视频文章80视频文章90视频文章100视频文章120视频文章140 视频2关键字专题关键字专题tag2tag3文章专题文章专题2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章专题3
当前位置: 首页 - 科技 - 知识百科 - 正文

ASP.NET Core Middleware的实现方法详解

来源:动视网 责编:小采 时间:2020-11-27 22:34:43
文档

ASP.NET Core Middleware的实现方法详解

ASP.NET Core Middleware的实现方法详解:概念 ASP.NET Core Middleware是在应用程序处理管道pipeline中用于处理请求和操作响应的组件。 每个组件: 在pipeline中判断是否将请求传递给下一个组件 在处理管道的下个组件执行之前和之后执行一些工作, HttpContxt对象能跨域请求、响应的执行
推荐度:
导读ASP.NET Core Middleware的实现方法详解:概念 ASP.NET Core Middleware是在应用程序处理管道pipeline中用于处理请求和操作响应的组件。 每个组件: 在pipeline中判断是否将请求传递给下一个组件 在处理管道的下个组件执行之前和之后执行一些工作, HttpContxt对象能跨域请求、响应的执行

//-----------------节选自 Microsoft.AspNetCore.Builder.UseMiddlewareExtensions------------------
 /// <summary>
 /// Adds a middleware type to the application's request pipeline.
 /// </summary>
 /// <typeparam name="TMiddleware">The middleware type.</typeparam>
 /// <param name="app">The <see cref="IApplicationBuilder"/> instance.</param>
 /// <param name="args">The arguments to pass to the middleware type instance's constructor.</param>
 /// <returns>The <see cref="IApplicationBuilder"/> instance.</returns>
 public static IApplicationBuilder UseMiddleware<TMiddleware>(this IApplicationBuilder app, params object[] args)
 {
 return app.UseMiddleware(typeof(TMiddleware), args);
 }
 /// <summary>
 /// Adds a middleware type to the application's request pipeline.
 /// </summary>
 /// <param name="app">The <see cref="IApplicationBuilder"/> instance.</param>
 /// <param name="middleware">The middleware type.</param>
 /// <param name="args">The arguments to pass to the middleware type instance's constructor.</param>
 /// <returns>The <see cref="IApplicationBuilder"/> instance.</returns>
 public static IApplicationBuilder UseMiddleware(this IApplicationBuilder app, Type middleware, params object[] args)
 {
 if (typeof(IMiddleware).GetTypeInfo().IsAssignableFrom(middleware.GetTypeInfo()))
 {
 // IMiddleware doesn't support passing args directly since it's
 // activated from the container
 if (args.Length > 0)
 {
 throw new NotSupportedException(Resources.FormatException_UseMiddlewareExplicitArgumentsNotSupported(typeof(IMiddleware)));
 }
 
 return UseMiddlewareInterface(app, middleware);
 }
 
 var applicationServices = app.ApplicationServices;
 return app.Use(next =>
 {
 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();
 
 if (invokeMethods.Length > 1)
 {
 throw new InvalidOperationException(Resources.FormatException_UseMiddleMutlipleInvokes(InvokeMethodName, InvokeAsyncMethodName));
 }
 
 if (invokeMethods.Length == 0)
 {
 throw new InvalidOperationException(Resources.FormatException_UseMiddlewareNoInvokeMethod(InvokeMethodName, InvokeAsyncMethodName, middleware));
 }
 
 var methodInfo = invokeMethods[0];
 if (!typeof(Task).IsAssignableFrom(methodInfo.ReturnType))
 {
 throw new InvalidOperationException(Resources.FormatException_UseMiddlewareNonTaskReturnType(InvokeMethodName, InvokeAsyncMethodName, nameof(Task)));
 }
 
 var parameters = methodInfo.GetParameters();
 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];
 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)methodInfo.CreateDelegate(typeof(RequestDelegate), instance);
 }
 // 当前执行委托除了可指定HttpContext参数以外, 还可以注入更多的依赖参数 
 var factory = Compile<object>(methodInfo, parameters);
 
 return context => 
 {
 var serviceProvider = context.RequestServices ?? applicationServices;
 if (serviceProvider == null)
 {
 throw new InvalidOperationException(Resources.FormatException_UseMiddlewareIServiceProviderNotAvailable(nameof(IServiceProvider)));
 }
 
 return factory(instance, context, serviceProvider);
 };
 });
 }
 
//-------------------节选自 Microsoft.AspNetCore.Builder.Internal.ApplicationBuilder-------------------
private readonly IList<Func<RequestDelegate, RequestDelegate>> _components = new List<Func<RequestDelegate, RequestDelegate>>();
 
publicIApplicationBuilder Use(Func<RequestDelegate,RequestDelegate>middleware)
{
 this._components.Add(middleware);
 return this;
}
 
 public RequestDelegate Build()
 {
 RequestDelegate app = context =>
 {
 context.Response.StatusCode = 404;
 return Task.CompletedTask;
 };
 
 foreach (var component in _components.Reverse())
 {
 app = component(app);
 }
 
 return app;
 }

通过以上代码我们可以看出:

  • 注册中间件的过程实际上,是给一个 Type= List<Func<RequestDelegate, RequestDelegate>> 的容器依次添加元素的过程;
  • 容器中每个元素对应每个中间件的行为委托Func<RequestDelegate, RequestDelegate> , 这个行为委托包含2个关键行为:输入下一个中间件的执行委托next:RequestDelegate, 完成当前中间件的Invoke函数: RequestDelegate;
  • 通过build方法完成前后中间件的链式传值关系
  • 分析源码:回答上面的问题:

    1. 使用反射构造中间件的时候,第一个参数Array[0] 是下一个中间件的执行委托
    2. 当前中间件执行委托 函数名称被限制为: Invoke/InvokeAsync, 函数支持传入除HttpContext之外的参数
    3. 按照代码顺序添加进入 _components容器, 通过后一个中间件的执行委托 -----(指向)----> 前一个中间件的输入执行委托建立链式关系。

    附:非标准中间件的用法

    短路中间件、 分叉中间件

    整个处理管道的形成,存在一些管道分叉或者临时插入中间件的行为,一些重要方法可供使用

  • Use方法是一个注册中间件的简便写法
  • Run方法是一个约定,一些中间件使用Run方法来完成管道的结尾
  • Map扩展方法:请求满足指定路径,将会执行分叉管道,强调满足 path
  • MapWhen方法:HttpContext满足条件,将会执行分叉管道:
  • UseWhen方法:选择性的注入中间件 
  • 总结

    文档

    ASP.NET Core Middleware的实现方法详解

    ASP.NET Core Middleware的实现方法详解:概念 ASP.NET Core Middleware是在应用程序处理管道pipeline中用于处理请求和操作响应的组件。 每个组件: 在pipeline中判断是否将请求传递给下一个组件 在处理管道的下个组件执行之前和之后执行一些工作, HttpContxt对象能跨域请求、响应的执行
    推荐度:
    标签: 方法 详解 core
    • 热门焦点

    最新推荐

    猜你喜欢

    热门推荐

    专题
    Top