我正在使用新的Asp.Net核心mvc应用程序。我定义了一个带有自定义约束的路由,它从网址设置当前的应用文化。我尝试通过创建自定义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的早期版本中,我有可能通过路由过程手动处理我的网址
var wrapper = new HttpContextWrapper(HttpContext.Current);
var routeData = RouteTable.Routes.GetRouteData(wrapper);
var language = routeData.GetValue("language")
我现在无法在新的framewrok中找到办法做同样的事情。另外,我想使用路径数据找出我的langugae,用一些字符串函数分析我的url字符串,找不到该语言。
答案 0 :(得分:10)
没有一种简单的方法可以做到这一点,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; }
}
答案 1 :(得分:1)
根据Ashley Lee的回答,这是一种优化的方法,可以防止重复配置路由。
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
// setup routes
var mvcRouter = BuildMvcRouter(app, routes =>
{
routes.MapRoute(
name: "custom",
template: "{language=fr-FR}/{controller=Home}/{action=Index}/{id?}");
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
};
// add route data initialization middleware
app.Use(next => SetRouteData(next, mvcRouter));
// add localization middleware
var requestLocalizationOptions = new RequestLocalizationOptions
{
DefaultRequestCulture = new RequestCulture("en-US")
};
requestLocalizationOptions.RequestCultureProviders.Clear();
requestLocalizationOptions.RequestCultureProviders.Add(
new MyCustomRequestCultureProvider()
);
app.UseRequestLocalization(requestLocalizationOptions);
// add mvc routing middleware
app.UseRouter(mvcRouter);
}
这取决于必须添加到StartUp类中的以下两个方法:
private static IRouter BuildMvcRouter(IApplicationBuilder app, Action<IRouteBuilder> configureRoutes)
{
if (app == null) throw new ArgumentNullException(nameof(app));
if (configureRoutes == null) throw new ArgumentNullException(nameof(configureRoutes));
app.ApplicationServices.GetRequiredService<MiddlewareFilterBuilder>().ApplicationBuilder = app.New();
RouteBuilder routeBuilder = new RouteBuilder(app)
{
DefaultHandler = app.ApplicationServices.GetRequiredService<MvcRouteHandler>()
};
configureRoutes((IRouteBuilder)routeBuilder);
routeBuilder.Routes.Insert(0, AttributeRouting.CreateAttributeMegaRoute(app.ApplicationServices));
return routeBuilder.Build();
}
private static RequestDelegate SetRouteData(RequestDelegate next, IRouter router)
{
return async context =>
{
var routeContext = new RouteContext(context);
await router.RouteAsync(routeContext);
if (routeContext.Handler != null)
{
context.Features[typeof(IRoutingFeature)] = new RoutingFeature()
{
RouteData = routeContext.RouteData
};
}
await next(context);
};
}
答案 2 :(得分:0)
通过添加“端点路由”功能使此操作变得更加容易。 本文介绍了如何使用端点路由功能https://aregcode.com/blog/2019/dotnetcore-understanding-aspnet-endpoint-routing/
var endpointFeature = context.Features[typeof(Microsoft.AspNetCore.Http.Features.IEndpointFeature)]
as Microsoft.AspNetCore.Http.Features.IEndpointFeature;
Microsoft.AspNetCore.Http.Endpoint endpoint = endpointFeature?.Endpoint;
//Note: endpoint will be null, if there was no
//route match found for the request by the endpoint route resolver middleware
if (endpoint != null)
{
var routePattern = (endpoint as Microsoft.AspNetCore.Routing.RouteEndpoint)?.RoutePattern
?.RawText;
Console.WriteLine("Name: " + endpoint.DisplayName);
Console.WriteLine($"Route Pattern: {routePattern}");
Console.WriteLine("Metadata Types: " + string.Join(", ", endpoint.Metadata));
}