// 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.
/// The instance.
/// The arguments to pass to the middleware type instance‘s constructor.
/// The instance.
public static IApplicationBuilder UseMiddleware(this IApplicationBuilder app, params object[] args)
{
return app.UseMiddleware(typeof(TMiddleware), args);
}
///
/// Adds a middleware type to the application‘s request pipeline.
///
/// The instance.
/// The middleware type.
/// The arguments to pass to the middleware type instance‘s constructor.
/// The instance.
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 = Compile
关键点我们看到 要在 自定义中间件中要实现 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");
}
}