我正在一个新的Asp.Net核心mvc应用程序。我定义了一个具有自定义约束的路由,它从URL中设置当前的应用程序文化。我想通过创建一个自定义的IRequestCultureProvider来管理我的应用程序的本地化,如下所示:
public class MyCustomRequestCultureProvider : IRequestCultureProvider { public Task<ProviderCultureResult> DetermineProviderCultureResult(HttpContext httpContext) { var language= httpContext.GetRouteValue("language"); var result = new ProviderCultureResult(language,language); return Task.FromResult(result); } }
我的MyCustomRequestCultureProvider在每个请求都被击中,这是可以的。我的问题是,在MVC的管道中,我的提供者DetermineProviderCultureResult方法在路由进程之前被命中,所以httpContext.GetRouteValue(“language”)总是返回null。
在以前的MVC版本中,我可以通过这样做通过路由过程来手动处理我的url
var wrapper = new HttpContextWrapper(HttpContext.Current); var routeData = RouteTable.Routes.GetRouteData(wrapper); var language = routeData.GetValue("language")
我现在找不到在新框架中做同样的事情的方法。另外,我想使用路由数据找出我的langugae,用一些字符串函数分析我的url字符串,以找到语言不是一个选项。
解决方法
没有一个简单的方法来做到这一点,ASP.Net团队还没有决定实现这个功能。 IRoutingFeature仅在MVC完成请求后才可用。
我能够组建一个解决方案,这个解决方案应该适合你。这将设置您传递到UseMvc()的路由以及所有属性路由以填充IRoutingFeature。完成之后,您可以通过httpContext.GetRouteValue(“language”);.
Startup.cs
public void Configure(IApplicationBuilder app,IHostingEnvironment env,ILoggerFactory loggerFactory) { // setup routes app.UseGetRoutesMiddleware(GetRoutes); // add localization var requestLocalizationOptions = new RequestLocalizationOptions { DefaultRequestCulture = new RequestCulture("en-US") }; requestLocalizationOptions.RequestCultureProviders.Clear(); requestLocalizationOptions.RequestCultureProviders.Add( new MyCustomRequestCultureProvider() ); app.UseRequestLocalization(requestLocalizationOptions); // add mvc app.UseMvc(GetRoutes); }
将路由移动到代理(用于重新使用),相同的文件/类:
private readonly Action<IRouteBuilder> GetRoutes = routes => { routes.MapRoute( name: "custom",template: "{language=fr-FR}/{controller=Home}/{action=Index}/{id?}"); routes.MapRoute( name: "default",template: "{controller=Home}/{action=Index}/{id?}"); };
添加新的中间件:
public static class GetRoutesMiddlewareExtensions { public static IApplicationBuilder UseGetRoutesMiddleware(this IApplicationBuilder app,Action<IRouteBuilder> configureRoutes) { if (app == null) { throw new ArgumentNullException(nameof(app)); } var routes = new RouteBuilder(app) { DefaultHandler = app.ApplicationServices.GetrequiredService<MvcRouteHandler>(),}; configureRoutes(routes); routes.Routes.Insert(0,AttributeRouting.CreateAttributeMegaRoute(app.ApplicationServices)); var router = routes.Build(); return app.UseMiddleware<GetRoutesMiddleware>(router); } } public class GetRoutesMiddleware { private readonly RequestDelegate next; private readonly IRouter _router; public GetRoutesMiddleware(RequestDelegate next,IRouter router) { this.next = next; _router = router; } public async Task Invoke(HttpContext httpContext) { var context = new RouteContext(httpContext); context.RouteData.Routers.Add(_router); await _router.RouteAsync(context); if (context.Handler != null) { httpContext.Features[typeof (IRoutingFeature)] = new RoutingFeature() { RouteData = context.RouteData,}; } // proceed to next... await next(httpContext); } }
你可能还要定义这个类呢
public class RoutingFeature : IRoutingFeature { public RouteData RouteData { get; set; } }