如何创建.NET Core中间件验证路由参数?解决路由约束注入异常
解决.NET Core 7 Razor Pages路由约束注入RequestLocalizationOptions的异常问题
问题原因
路由约束是在路由构建阶段初始化的,这个阶段DI容器的初始化尚未完成,直接在路由约束的构造函数中注入RequestLocalizationOptions会触发RouteCreationException——因为路由系统无法在路由定义阶段解析依赖服务。硬编码有效文化列表能正常工作,是因为它不需要依赖DI容器。
解决方案:两种可行方案
方案1:调整路由约束的依赖获取方式
不要直接在构造函数注入RequestLocalizationOptions,而是通过IServiceProvider在请求时动态获取服务,避开路由构建阶段的DI限制:
- 修改自定义路由约束:
public class CultureRouteConstraint : IRouteConstraint { private readonly IServiceProvider _serviceProvider; public CultureRouteConstraint(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; } public bool Match(HttpContext httpContext, IRouter route, string routeKey, RouteValueDictionary values, RouteDirection routeDirection) { if (!values.TryGetValue(routeKey, out var cultureValue) || cultureValue is not string culture) return false; // 在请求时动态获取本地化配置 var localizationOptions = _serviceProvider.GetRequiredService<IOptions<RequestLocalizationOptions>>().Value; var validCultures = localizationOptions.SupportedCultures.Select(c => c.Name).ToList(); return validCultures.Contains(culture, StringComparer.OrdinalIgnoreCase); } }
- 在Program.cs中注册约束和本地化配置:
var builder = WebApplication.CreateBuilder(args); // 配置本地化选项 builder.Services.Configure<RequestLocalizationOptions>(options => { var supportedCultures = new[] { "en", "pt" }; options.DefaultRequestCulture = new RequestCulture("en"); options.SupportedCultures = supportedCultures.Select(c => new CultureInfo(c)).ToList(); options.SupportedUICultures = options.SupportedCultures; }); // 注册自定义路由约束 builder.Services.AddRouting(options => { options.ConstraintMap.Add("validculture", typeof(CultureRouteConstraint)); }); builder.Services.AddRazorPages(); var app = builder.Build(); // 启用本地化中间件 app.UseRequestLocalization(); app.UseRouting(); app.UseAuthorization(); app.MapRazorPages(); app.Run();
方案2:改用中间件实现文化验证
如果路由约束的DI问题难以调试,中间件是更灵活的替代方案——中间件运行在请求管道中,DI容器已完全初始化,可直接注入依赖:
- 修改Razor页面的路由,移除
validculture约束:
@page "/{culture}/about"
- 创建文化验证中间件:
public class CultureValidationMiddleware { private readonly RequestDelegate _next; public CultureValidationMiddleware(RequestDelegate next) { _next = next; } public async Task InvokeAsync(HttpContext context, IOptions<RequestLocalizationOptions> localizationOptions) { if (context.Request.RouteValues.TryGetValue("culture", out var cultureValue) && cultureValue is string culture) { var validCultures = localizationOptions.Value.SupportedCultures.Select(c => c.Name).ToList(); if (!validCultures.Contains(culture, StringComparer.OrdinalIgnoreCase)) { context.Response.StatusCode = StatusCodes.Status404NotFound; // 可自定义返回内容,比如返回项目中的404页面 await context.Response.WriteAsync("Invalid culture specified"); return; } } await _next(context); } }
- 在Program.cs中注册中间件(注意放在路由中间件之后,端点映射之前):
var app = builder.Build(); // 其他中间件配置... app.UseRequestLocalization(); app.UseRouting(); // 注册文化验证中间件 app.UseMiddleware<CultureValidationMiddleware>(); app.UseAuthorization(); app.MapRazorPages(); app.Run();
方案对比
- 路由约束方案:更贴合路由系统的设计,验证逻辑与路由定义绑定,适合简单的参数校验场景。
- 中间件方案:灵活性更高,可处理更复杂的验证逻辑(比如结合数据库查询验证文化),且DI使用更直观,避免路由构建阶段的依赖问题。
内容的提问来源于stack exchange,提问作者Miguel Moura
相关产品推荐
相关产品推荐

