public class Middleware { private readonly RequestDelegate _next; public RouterMiddleware(RequestDelegate next) { _next = next; } public async Task Invoke(HttpContext httpContext) { // do something await _next.Invoke(httpContext); // do something } }
namespace Microsoft.AspNetCore.Builder.Internal { public class ApplicationBuilder : IApplicationBuilder { private readonly IList<Func<RequestDelegate, RequestDelegate>> _components = new List<Func<RequestDelegate, RequestDelegate>>(); public IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware) { _components.Add(middleware); return this; } } }
ApplicationBuilder.Build
方法會處理全部註冊的中間件生成的委託集合,將全部中間件生成的委託集合,處理成嵌套的形式,最終獲得一個委託,連成一段管道。Reverse
方法將集合反轉,從最後註冊的中間件對應的委託開始處理Startup.cs
類裏面的Configure
方法,裏面的每一個Use開頭的方法都對應一箇中間件註冊,代碼的順序就是註冊的順序,也是執行的順序,千萬不能寫錯了。由於MVC處於處理流程的最後面,所以UseMvc方法老是位於最後component
,是從_components
委託集合裏面取出來的,執行後又獲得一個RequestDelegate
類型的委託,所以由中間件生成的委託的類型應該是Func<RequestDelegate, RequestDelegate>
public RequestDelegate Build() { RequestDelegate app = context => { context.Response.StatusCode = 404; return Task.CompletedTask; }; foreach (var component in _components.Reverse()) { app = component(app); } return app; }
ApplicationBuilder.Use
方法,將中間件生成的委託加入委託集合,完成中間件註冊app.Use
方法參數,就是上面須要的類型Func<RequestDelegate, RequestDelegate>
的委託,該委託的參數next
就是下一個中間件對應的委託,返回值就是中間件的Invoke
方法對應的委託,該方法用到了next
public static IApplicationBuilder UseMiddleware<TMiddleware>(this IApplicationBuilder app, params object[] args) { return app.UseMiddleware(typeof(TMiddleware), args); } public static IApplicationBuilder UseMiddleware(this IApplicationBuilder app, Type middleware, params object[] args) { // 省略部分代碼 var applicationServices = app.ApplicationServices; return app.Use(next => { // 省略部分代碼 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); }; }); }
IMiddleware
接口,則調用UseMiddlewareInterface
方法。使用了接口規範,那麼你也不能亂寫了,只須要注意在Invoke
方法調用next
便可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 factory throw new InvalidOperationException(Resources.FormatException_UseMiddlewareNoMiddlewareFactory(typeof(IMiddlewareFactory))); } var middleware = middlewareFactory.Create(middlewareType); if (middleware == null) { // The factory returned null, it's a broken implementation throw new InvalidOperationException(Resources.FormatException_UseMiddlewareUnableToCreateMiddleware(middlewareFactory.GetType(), middlewareType)); } try { await middleware.InvokeAsync(context, next); } finally { middlewareFactory.Release(middleware); } }; }); }
Invoke
或InvokeAsync
的一個方法public static class UseMiddlewareExtensions { internal const string InvokeMethodName = "Invoke"; internal const string InvokeAsyncMethodName = "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)); }
Task
var methodinfo = invokeMethods[0]; if (!typeof(Task).IsAssignableFrom(methodinfo.ReturnType)) { throw new InvalidOperationException(Resources.FormatException_UseMiddlewareNonTaskReturnType(InvokeMethodName, InvokeAsyncMethodName, nameof(Task))); }
HttpContext
var parameters = methodinfo.GetParameters(); if (parameters.Length == 0 || parameters[0].ParameterType != typeof(HttpContext)) { throw new InvalidOperationException(Resources.FormatException_UseMiddlewareNoParameters(InvokeMethodName, InvokeAsyncMethodName, nameof(HttpContext))); }
UseMiddleware
方法傳入的自定義參數args
加上下一個委託next
,獲得新的參數數組,而後建立中間件實例,生成Invoke
方法對應委託。此處注意,若是中間件的構造函數中有其它參數,可是未註冊到ApplicationServices
的話,須要在UseMiddleware
方法中傳入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); }
Compile
方法,生成一個委託,該委託從IServiceProvider
中獲取須要的參數的實例,再調用Invoke
方法,相比上面的狀況,多了一步從IServiceProvider
獲取實例,注入到Invoke
而已。Compile
方法使用了Linq表達式樹,源碼位於Microsoft.AspNetCore.Builder.UseMiddlewareExtensions,此處不做講解,由於我也不太懂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); };
最後,文章可能有更新,請閱讀原文得到更好的體驗哦 http://www.javashuo.com/article/p-uggknsul-hn.htmlhtml