Middleware理解 Applicationbuilder维护着一个中间件集合
1 private readonly IList<Func<RequestDelegate, RequestDelegate>> _components = new List<Func<RequestDelegate, RequestDelegate>>();
本质都是是往ApplicationBuilder对象的_components成员里添加中间件Func<RequestDelegate, RequestDelegate>
1 2 3 public delegate Task RequestDelegate (HttpContext context ) ;private readonly IList<Func<RequestDelegate, RequestDelegate>> _components
通过传值和返回都是RequestDelegate委托,对HttpContext的处理,各个中间件首尾相连,形似管道
Middleware使用 ApplicationBuilder添加中间件 ApplicationBuilder实例方法 1 2 3 4 5 6 7 8 9 10 11 12 namespace Microsoft.AspNetCore.Builder { public IApplicationBuilder Use (Func<RequestDelegate, RequestDelegate> middleware ) { _components.Add(middleware); return this ; } }
ApplicationBuilder拓展方法
1 2 3 4 public static IApplicationBuilder UseMiddleware <TMiddleware >(this IApplicationBuilder app, params object [] args ){ return app.UseMiddleware(typeof (TMiddleware), args); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 public static IApplicationBuilder UseMiddleware <TMiddleware >(this IApplicationBuilder app, Type middleware, params object [] args ){ if (typeof (IMiddleware).GetTypeInfo().IsAssignableFrom(middleware.GetTypeInfo())) { return UseMiddlewareInterface(app, middleware); } var applicationServices = app.ApplicationServices; return app.Use(next => { var methods = middleware.GetMethods(BindingFlags.Instance | BindingFlags.Public); var invokeMethods = methods.Where(m => string .Equals(m.Name, InvokeMethodName, StringComparison.Ordinal) || string .Equals(m.Name, InvokeAsyncMethodName, StringComparison.Ordinal) ).ToArray(); var methodInfo = invokeMethods[0 ]; var parameters = methodInfo.GetParameters(); 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); } 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); }; } }
1 2 3 4 public static IApplicationBuilder Map (this IApplicationBuilder app, PathString pathMatch, Action<IApplicationBuilder> configuration ){ return Map(app, pathMatch, preserveMatchedPathSegment: false , configuration); }
核心方法,通过pathMatch参数判断给中间件加上执行条件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public static IApplicationBuilder Map (this IApplicationBuilder app, PathString pathMatch, bool preserveMatchedPathSegment, Action<IApplicationBuilder> configuration ){ var branchBuilder = app.New(); configuration(branchBuilder); var branch = branchBuilder.Build(); var options = new MapOptions { Branch = branch, PathMatch = pathMatch, PreserveMatchedPathSegment = preserveMatchedPathSegment }; return app.Use(next => new MapMiddleware(next, options).Invoke); }
MapMiddleware
是对RequestDelegate
的进一步封装,增加MapOptions
,通过Invoke方法,形成一个中间件
1 Func<RequestDelegate,RequestDelegate> = (RequestDelegate next) = new MapMiddleware(next,options).Invoke
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 public class MapMiddleware { private readonly RequestDelegate _next; private readonly MapOptions _options; public async Task Invoke (HttpContext context ) { if (context.Request.Path.StartsWithSegments(_options.PathMatch, out var matchedPath, out var remainingPath)) { var path = context.Request.Path; var pathBase = context.Request.PathBase; if (!_options.PreserveMatchedPathSegment) { context.Request.PathBase = pathBase.Add(matchedPath); context.Request.Path = remainingPath; } try { await _options.Branch(context); } finally { if (!_options.PreserveMatchedPathSegment) { context.Request.PathBase = pathBase; context.Request.Path = path; } } } else { await _next(context); } } }
MapWhen 通过WhenMapOptions条件匹配路由
这种方式更具有拓展性,相比较Map判断逻辑写在Invoke方法里,这个可以匹配规则通过传递委托形式自定义
1 2 3 4 public class WhenMapOptions { private Func<HttpContext, bool > _predicate; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public static IApplicationBuilder MapWhen (this IApplicationBuilder app, Predicate predicate, Action<IApplicationBuilder> configuration ){ var branchBuilder = app.New(); configuration(branchBuilder); var branch = branchBuilder.Build(); var options = new MapWhenOptions { Predicate = predicate, Branch = branch, }; return app.Use(next => new MapWhenMiddleware(next, options).Invoke); }
Run 在管道增加终端中间件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public static void Run (this IApplicationBuilder app, RequestDelegate handler ){ if (app == null ) { throw new ArgumentNullException(nameof (app)); } if (handler == null ) { throw new ArgumentNullException(nameof (handler)); } app.Use(_ => handler); }
ApplicationBuilder构建管道 通过Build()方法,构建最终管道
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 public RequestDelegate Build (){ RequestDelegate app = context => { var endpoint = context.GetEndpoint(); var endpointRequestDelegate = endpoint?.RequestDelegate; if (endpointRequestDelegate != null ) { var message = $"The request reached the end of the pipeline without executing the endpoint: '{endpoint.DisplayName} '. " + $"Please register the EndpointMiddleware using '{nameof (IApplicationBuilder)} .UseEndpoints(...)' if using " + $"routing." ; throw new InvalidOperationException(message); } context.Response.StatusCode = StatusCodes.Status404NotFound; return Task.CompletedTask; }; foreach (var component in _components.Reverse()) { app = component(app); } return app; }
Middleware用法
1 2 3 4 5 6 7 8 9 10 11 12 13 public class Startup { public void Configure (IApplicationBuilder app ) { app.Use(async (context, next) => { Console.WriteLine("A (in)" ); await next(); Console.WriteLine("A (out)" ); }); } }
有两种方式一种是实现IMiddleware,还有一种是符合中间件规范并提供同步Invoke方法或者异步InvokeAsync
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 public class Startup { public void Configure (IApplicationBuilder app ) { app.UseMiddleware<MiddlewareB>(); } } public class MiddlewareB { private readonly RequestDelegate _next; public MiddlewareB (RequestDelegate next ) { _next = next; } public async Task InvokeAsync (HttpContext httpContext ) { Console.WriteLine("B (in)" ); _next.Invoke(httpContext); Console.WriteLine("B (out)" ); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class Startup { public void Configure (IApplicationBuilder app ) { app.Map( new PathString("/foo" ), a => a.Use(async (context, next) => { Console.WriteLine("B (in)" ); await next(); Console.WriteLine("B (out)" ); })); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class Startup { public void Configure (IApplicationBuilder app ) { app.UseWhen( context => context.Request.Path.StartsWithSegments(new PathString("/foo" )), a => a.Use(async (context, next) => { Console.WriteLine("B (in)" ); await next(); Console.WriteLine("B (out)" ); })); } }
1 2 3 4 5 6 7 8 9 10 11 12 public class Startup { public void Configure (IApplicationBuilder app ) { app.Run(async context => { Console.WriteLine("C" ); await context.Response.WriteAsync("Hello World from the terminal middleware" ); }); } }
官方中间件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class HealthCheckMiddleware { private readonly RequestDelegate _next; private readonly HealthCheckOptions _healthCheckOptions; private readonly HealthCheckService _healthCheckService; public HealthCheckMiddleware ( RequestDelegate next, HealthCheckOptions healthCheckOptions, HealthCheckService healthCheckService ) { _next = next; _healthCheckOptions = healthCheckOptions; _healthCheckService = healthCheckService } public async Task InvokeAsync (HttpContext httpContext ) { } }
本质上跟MapMiddleware实现是一样的,包括自定义中间件也可以这样实现