添加自定义中间件在使用 IMiddleware 时不起作用
Adding custom middleware not working when using IMiddleware
我正在尝试向管道添加自定义中间件(为了更容易,我将选择 .NET Core 文档示例)。
假设我们希望在触发对 API 的调用时设置西班牙文化。
这是 运行 完美的代码:
public class RequestCultureMiddleware
{
private readonly RequestDelegate _next;
public RequestCultureMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
CultureInfo.CurrentCulture = new CultureInfo("es-ES");
CultureInfo.CurrentUICulture = new CultureInfo("es-ES");
// Call the next delegate/middleware in the pipeline
await _next(context);
}
}
public static class RequestCultureMiddlewareExtensions
{
public static IApplicationBuilder UseRequestCulture(
this IApplicationBuilder builder)
{
return builder.UseMiddleware<RequestCultureMiddleware>();
}
}
和启动 class:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
//here is our custom middleware!
app.UseRequestCulture();
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
很好,但是如您所见,RequestCultureMiddleware 没有实现接口或基础 class/abstract class。您只需要记住在定义中间件时创建接收下一个中间件的构造函数,还需要创建一个专门调用 "InvokeAsync" 并使用 "HttpContext" 作为参数的方法。
我试图找到一个合同...一个基础 class 或一个接口,你猜怎么着,我们有 "IMiddleware",它是 "Microsoft.AspNetCore.Http" 程序集的一部分。哇,太完美了。让我们来实施吧。
界面是这样的:
namespace Microsoft.AspNetCore.Http
{
//
// Summary:
// Defines middleware that can be added to the application's request pipeline.
public interface IMiddleware
{
//
// Summary:
// Request handling method.
//
// Parameters:
// context:
// The Microsoft.AspNetCore.Http.HttpContext for the current request.
//
// next:
// The delegate representing the remaining middleware in the request pipeline.
//
// Returns:
// A System.Threading.Tasks.Task that represents the execution of this middleware.
Task InvokeAsync(HttpContext context, RequestDelegate next);
}
}
这里是实现:
public class RequestCultureMiddleware : IMiddleware
{
public Task InvokeAsync(HttpContext context, RequestDelegate next)
{
CultureInfo.CurrentCulture = new CultureInfo("es-ES");
CultureInfo.CurrentUICulture = new CultureInfo("es-ES");
// Call the next delegate/middleware in the pipeline
return next(context);
}
}
public static class RequestCultureMiddlewareExtensions
{
public static IApplicationBuilder UseRequestCulture(
this IApplicationBuilder builder)
{
return builder.UseMiddleware<RequestCultureMiddleware>();
}
}
}
但是,当 运行 连接 API 时,我在 运行 时收到以下错误:
System.InvalidOperationException: No service for type 'WebApplication1.RequestCultureMiddleware' has been registered.
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
at Microsoft.AspNetCore.Http.MiddlewareFactory.Create(Type middlewareType)
at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.<>c__DisplayClass5_1.<<UseMiddlewareInterface>b__1>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
如果不使用扩展 "UseMiddleware",我应该如何注册这个中间件?
谢谢。
您正在使用 factory-based middleware。如这些文档中所述,您错过了重要的一步:
... the IMiddlewareFactory instance registered in the container is used to resolve the IMiddleware implementation instead of using the convention-based middleware activation logic. The middleware is registered as a scoped or transient service in the app's service container.
在您的情况下,该注册看起来像这样:
public void ConfigureServices(IServiceCollection services)
{
// ...
services.AddTransient<RequestCultureMiddleware>();
}
我确定这个问题在 5 个月后很久以前就已经解决了,但我写这个建议是为了以防万一。
问题是您的自定义中间件程序的“InvokeAsync”方法没有被执行,即使您在 Startup 的“Configure”方法中内置了它。
前几天我遇到了同样的问题并解决了它,但是我在 app.UseEndpoints 方法之前放置了内置代码。
你的情况
app.UseAuthorization();
app.UseRequestCulture(); // <- this way.
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
顺便说一下,如果你把它放在app.UseEndpoints方法之后,构造函数会被调用,但是InvokeAsync方法不会被执行。
我正在尝试向管道添加自定义中间件(为了更容易,我将选择 .NET Core 文档示例)。 假设我们希望在触发对 API 的调用时设置西班牙文化。 这是 运行 完美的代码:
public class RequestCultureMiddleware
{
private readonly RequestDelegate _next;
public RequestCultureMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
CultureInfo.CurrentCulture = new CultureInfo("es-ES");
CultureInfo.CurrentUICulture = new CultureInfo("es-ES");
// Call the next delegate/middleware in the pipeline
await _next(context);
}
}
public static class RequestCultureMiddlewareExtensions
{
public static IApplicationBuilder UseRequestCulture(
this IApplicationBuilder builder)
{
return builder.UseMiddleware<RequestCultureMiddleware>();
}
}
和启动 class:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
//here is our custom middleware!
app.UseRequestCulture();
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
很好,但是如您所见,RequestCultureMiddleware 没有实现接口或基础 class/abstract class。您只需要记住在定义中间件时创建接收下一个中间件的构造函数,还需要创建一个专门调用 "InvokeAsync" 并使用 "HttpContext" 作为参数的方法。
我试图找到一个合同...一个基础 class 或一个接口,你猜怎么着,我们有 "IMiddleware",它是 "Microsoft.AspNetCore.Http" 程序集的一部分。哇,太完美了。让我们来实施吧。
界面是这样的:
namespace Microsoft.AspNetCore.Http
{
//
// Summary:
// Defines middleware that can be added to the application's request pipeline.
public interface IMiddleware
{
//
// Summary:
// Request handling method.
//
// Parameters:
// context:
// The Microsoft.AspNetCore.Http.HttpContext for the current request.
//
// next:
// The delegate representing the remaining middleware in the request pipeline.
//
// Returns:
// A System.Threading.Tasks.Task that represents the execution of this middleware.
Task InvokeAsync(HttpContext context, RequestDelegate next);
}
}
这里是实现:
public class RequestCultureMiddleware : IMiddleware
{
public Task InvokeAsync(HttpContext context, RequestDelegate next)
{
CultureInfo.CurrentCulture = new CultureInfo("es-ES");
CultureInfo.CurrentUICulture = new CultureInfo("es-ES");
// Call the next delegate/middleware in the pipeline
return next(context);
}
}
public static class RequestCultureMiddlewareExtensions
{
public static IApplicationBuilder UseRequestCulture(
this IApplicationBuilder builder)
{
return builder.UseMiddleware<RequestCultureMiddleware>();
}
}
}
但是,当 运行 连接 API 时,我在 运行 时收到以下错误:
System.InvalidOperationException: No service for type 'WebApplication1.RequestCultureMiddleware' has been registered.
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
at Microsoft.AspNetCore.Http.MiddlewareFactory.Create(Type middlewareType)
at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.<>c__DisplayClass5_1.<<UseMiddlewareInterface>b__1>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
如果不使用扩展 "UseMiddleware",我应该如何注册这个中间件? 谢谢。
您正在使用 factory-based middleware。如这些文档中所述,您错过了重要的一步:
... the IMiddlewareFactory instance registered in the container is used to resolve the IMiddleware implementation instead of using the convention-based middleware activation logic. The middleware is registered as a scoped or transient service in the app's service container.
在您的情况下,该注册看起来像这样:
public void ConfigureServices(IServiceCollection services)
{
// ...
services.AddTransient<RequestCultureMiddleware>();
}
我确定这个问题在 5 个月后很久以前就已经解决了,但我写这个建议是为了以防万一。
问题是您的自定义中间件程序的“InvokeAsync”方法没有被执行,即使您在 Startup 的“Configure”方法中内置了它。
前几天我遇到了同样的问题并解决了它,但是我在 app.UseEndpoints 方法之前放置了内置代码。
你的情况
app.UseAuthorization();
app.UseRequestCulture(); // <- this way.
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
顺便说一下,如果你把它放在app.UseEndpoints方法之后,构造函数会被调用,但是InvokeAsync方法不会被执行。