Tse*_*eng 10 routes asp.net-core-mvc asp.net-core asp.net-core-1.0
我试图覆盖当前请求的文化.我使用自定义部分工作ActionFilterAttribute.
public sealed class LanguageActionFilter : ActionFilterAttribute
{
private readonly ILogger logger;
private readonly IOptions<RequestLocalizationOptions> localizationOptions;
public LanguageActionFilter(ILoggerFactory loggerFactory, IOptions<RequestLocalizationOptions> options)
{
if (loggerFactory == null)
throw new ArgumentNullException(nameof(loggerFactory));
if (options == null)
throw new ArgumentNullException(nameof(options));
logger = loggerFactory.CreateLogger(nameof(LanguageActionFilter));
localizationOptions = options;
}
public override void OnActionExecuting(ActionExecutingContext context)
{
string culture = context.RouteData.Values["culture"]?.ToString();
if (!string.IsNullOrWhiteSpace(culture))
{
logger.LogInformation($"Setting the culture from the URL: {culture}");
#if DNX46
System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo(culture);
System.Threading.Thread.CurrentThread.CurrentUICulture = new CultureInfo(culture);
#else
CultureInfo.CurrentCulture = new CultureInfo(culture);
CultureInfo.CurrentUICulture = new CultureInfo(culture);
#endif
}
base.OnActionExecuting(context);
}
}
Run Code Online (Sandbox Code Playgroud)
在控制器上我使用LanguageActionFilter.
[ServiceFilter(typeof(LanguageActionFilter))]
[Route("api/{culture}/[controller]")]
public class ProductsController : Controller
{
...
}
Run Code Online (Sandbox Code Playgroud)
这项工作到目前为止,但我有两个问题:
{culture}在每个控制器上声明,因为我将在每条路线上都需要它.[Route("api/{culture=en-US}/[controller]")]显而易见的原因.设置默认路由结果也不起作用.
app.UseMvc( routes =>
{
routes.MapRoute(
name: "DefaultRoute",
template: "api/{culture=en-US}/{controller}"
);
});
Run Code Online (Sandbox Code Playgroud)
我还调查了自定义IRequestCultureProvider实现并将其添加到UseRequestLocalization方法中
app.UseRequestLocalization(new RequestLocalizationOptions
{
RequestCultureProviders = new List<IRequestCultureProvider>
{
new UrlCultureProvider()
},
SupportedCultures = new List<CultureInfo>
{
new CultureInfo("de-de"),
new CultureInfo("en-us"),
new CultureInfo("en-gb")
},
SupportedUICultures = new List<CultureInfo>
{
new CultureInfo("de-de"),
new CultureInfo("en-us"),
new CultureInfo("en-gb")
}
}, new RequestCulture("en-US"));
Run Code Online (Sandbox Code Playgroud)
但后来我无法访问那里的路线(我假设路由是在管道中稍后完成的).当然我也可以尝试解析请求的URL.我甚至不知道我是否可以改变这个地方的路线,这样就可以将上述路线与其中的文化相匹配.
通过查询参数传递文化或更改路径内参数的顺序不是一种选择.
api/en-us/products我们的两个网址api/products应该路由到同一个控制器,前者不会改变文化.
确定文化的顺序应该是
Accept-Language标头.2-4通过UseRequestLocalization并且有效.另外,我不喜欢当前的方法必须为每个控制器添加两个属性({culture}在路由和中[ServiceFilter(typeof(LanguageActionFilter))]).
编辑:
我还想将有效语言环境的数量限制SupportedCultures为RequestLocalizationOptions传递给的属性中的一个UseRequestLocalization.
IOptions<RequestLocalizationOptions> localizationOptions在LanguageActionFilter上述方法无效,因为它返回一个新的实例RequestLocalizationOptions,其中SupportedCultures始终null,而不是一个传递给.
FWIW它是一个RESTful WebApi项目.
Dan*_*.G. 23
更新ASP.Net Core 1.1
新版本RouteDataRequestCultureProvider将作为1.1 版本的一部分发布,这有望意味着您不再需要创建自己的请求提供程序.您仍然可以在此处找到有用的信息(如路由位),或者您可能有兴趣创建自己的请求文化提供程序.
您可以创建2条路线,让您可以在网址中使用和不包含文化细分来访问您的终结点.双方/api/en-EN/home并/api/home会被路由到归属控制器.(因此/api/blah/home不会与具有文化的路线匹配,并且因为不存在blah控制器而将获得404)
要使这些路由起作用,包含culture参数的路由具有更高的首选项,culture参数包含正则表达式:
app.UseMvc(routes =>
{
routes.MapRoute(
name: "apiCulture",
template: "api/{culture:regex(^[a-z]{{2}}-[A-Z]{{2}}$)}/{controller}/{action=Index}/{id?}");
routes.MapRoute(
name: "defaultApi",
template: "api/{controller}/{action=Index}/{id?}");
});
Run Code Online (Sandbox Code Playgroud)
上述路由将与MVC样式控制器一起使用,但如果使用wb api样式的控制器构建休息接口,则属性路由是MVC 6中的首选方式.
一种选择是使用属性路由,但是如果你可以设置url的基本段,则为所有api控制器使用基类:
[Route("api/{language:regex(^[[a-z]]{{2}}-[[A-Z]]{{2}}$)}/[controller]")]
[Route("api/[controller]")]
public class BaseApiController: Controller
{
}
public class ProductController : BaseApiController
{
//This will bind to /api/product/1 and /api/en-EN/product/1
[HttpGet("{id}")]
public IActionResult GetById(string id)
{
return new ObjectResult(new { foo = "bar" });
}
}
Run Code Online (Sandbox Code Playgroud)避免基类而不需要太多自定义代码的快速方法是通过web api兼容性垫片:
"Microsoft.AspNet.Mvc.WebApiCompatShim": "6.0.0-rc1-final"添加垫片约定:
services.AddMvc().AddWebApiConventions();
Run Code Online (Sandbox Code Playgroud)ApiControllershim包添加的控制器使用te MapApiRoute重载定义包含culture参数的路由:
routes.MapWebApiRoute("apiLanguage",
"api/{language:regex(^[a-z]{{2}}-[A-Z]{{2}}$)}/{controller}/{id?}");
routes.MapWebApiRoute("DefaultApi",
"api/{controller}/{id?}");
Run Code Online (Sandbox Code Playgroud)更清晰,更好的选择是创建和应用您自己的选项IApplicationModelConvention,负责为您的属性路由添加区域性前缀.这超出了这个问题的范围,但我已经实现了本本地化文章的想法
然后你需要创建一个新的IRequestCultureProvider,它将查看请求URL并从那里提取文化(如果提供).
升级到ASP .Net Core 1.1后,您可以避免手动解析请求URL并提取文化段.
我检查了ASP.Net Core 1.1中的实现
RouteDataRequestCultureProvider,他们使用HttpContext扩展方法GetRouteValue(string)获取请求提供程序中的url段:Run Code Online (Sandbox Code Playgroud)culture = httpContext.GetRouteValue(RouteDataStringKey)?.ToString();但是我怀疑(我还没有机会尝试它),这只有在将中间件添加为MVC过滤器时才有效.这样你的中间件就可以在路由中间件之后运行,这是将其添加
IRoutingFeature到HttpContext中的中间件.作为快速测试,在UseMvc之前添加以下中间件将不会获得路由数据:Run Code Online (Sandbox Code Playgroud)app.Use(async (context, next) => { //always null var routeData = context.GetRouteData(); await next(); });
为了实现新的IRequestCultureProvider你需要:
实现将如下所示:
public class UrlCultureProvider : IRequestCultureProvider
{
public Task<ProviderCultureResult> DetermineProviderCultureResult(HttpContext httpContext)
{
var url = httpContext.Request.Path;
//Quick and dirty parsing of language from url path, which looks like "/api/de-DE/home"
//This could be skipped after 1.1 if using the middleware as an MVC filter
//since you will be able to just call the method GetRouteValue("culture")
//on the HttpContext and retrieve the route value
var parts = httpContext.Request.Path.Value.Split('/');
if (parts.Length < 3)
{
return Task.FromResult<ProviderCultureResult>(null);
}
var hasCulture = Regex.IsMatch(parts[2], @"^[a-z]{2}-[A-Z]{2}$");
if (!hasCulture)
{
return Task.FromResult<ProviderCultureResult>(null);
}
var culture = parts[2];
return Task.FromResult(new ProviderCultureResult(culture));
}
}
Run Code Online (Sandbox Code Playgroud)
最后启用本地化功能,包括新的提供程序,作为支持的提供程序列表中的第一个.当它们按顺序进行评估并且第一个返回非空结果时,您的提供程序将优先,接下来将是默认值(查询字符串,cookie和标题).
var localizationOptions = new RequestLocalizationOptions
{
SupportedCultures = new List<CultureInfo>
{
new CultureInfo("de-DE"),
new CultureInfo("en-US"),
new CultureInfo("en-GB")
},
SupportedUICultures = new List<CultureInfo>
{
new CultureInfo("de-DE"),
new CultureInfo("en-US"),
new CultureInfo("en-GB")
}
};
//Insert this at the beginning of the list since providers are evaluated in order until one returns a not null result
localizationOptions.RequestCultureProviders.Insert(0, new UrlCultureProvider());
//Add request localization middleware
app.UseRequestLocalization(localizationOptions, new RequestCulture("en-US"));
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
6831 次 |
| 最近记录: |