上一篇我们知道可以使用 app.use 注册中间件,但是 这样都写在 Startup 文件可能不是我们想要的。.NET Core 提供了 使用 UseMiddlewareExtensions 扩展中间件。我们看一下需要什么。
// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Abstractions; using Microsoft.Extensions.Internal; namespace Microsoft.AspNetCore.Builder { ////// Extension methods for adding typed middleware. /// public static class UseMiddlewareExtensions { internal const string InvokeMethodName = "Invoke"; internal const string InvokeAsyncMethodName = "InvokeAsync"; private static readonly MethodInfo GetServiceInfo = typeof(UseMiddlewareExtensions).GetMethod(nameof(GetService), BindingFlags.NonPublic | BindingFlags.Static)!; ////// Adds a middleware type to the application's request pipeline. /// ///The middleware type. /// Theinstance. /// The arguments to pass to the middleware type instance's constructor. /// The public static IApplicationBuilder UseMiddlewareinstance. (this IApplicationBuilder app, params object[] args) { return app.UseMiddleware(typeof(TMiddleware), args); } /// /// Adds a middleware type to the application's request pipeline. /// /// Theinstance. /// The middleware type. /// The arguments to pass to the middleware type instance's constructor. /// The 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); 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); } var factory = Compileinstance.
关键点我们看到 要在 自定义中间件中要实现 Invoke 或 InvokeAsync 方法
并且在构造函数中 注册了 next ->RequestDelegate
所以有了上面的基础,我们可以方面实现自定义中间件。
public class CustomMiddleWare { private readonly RequestDelegate _next; public CustomMiddleWare(RequestDelegate next) { _next = next; } public async Task Invoke(HttpContext context) { await context.Response.WriteAsync($"{nameof(CustomMiddleWare)},Hello World1!
"); await _next(context); await context.Response.WriteAsync($"{nameof(CustomMiddleWare)},Hello World2"); } }
在 Startup 文件中注册即可。