gpt4 book ai didi

routes - 可选择通过 ASP.NET Core 1.0 应用程序中的 url/route 覆盖请求区域性

转载 作者:行者123 更新时间:2023-12-04 02:52:04 26 4
gpt4 key购买 nike

我正在尝试覆盖当前请求的文化。我使用自定义 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);
}
}

在 Controller 上,我使用 LanguageActionFilter .

[ServiceFilter(typeof(LanguageActionFilter))]
[Route("api/{culture}/[controller]")]
public class ProductsController : Controller
{
...
}

到目前为止,这有效,但我有两个问题:
  • 我不喜欢必须声明 {culture}在每个 Controller 上,因为我将在每条路线上都需要它。
  • 我的默认文化不适用于这种方法,即使我将其声明为 [Route("api/{culture=en-US}/[controller]")]出于显而易见的原因。

  • 设置默认路由结果也不起作用。

    app.UseMvc( routes =>
    {
    routes.MapRoute(
    name: "DefaultRoute",
    template: "api/{culture=en-US}/{controller}"
    );
    });

    我也在一个自定义 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"));

    但后来我无法访问那里的路线(我假设是因为路线稍后在管道中完成)。当然我也可以尝试解析请求的 url。而且我什至不知道我是否可以改变这个地方的路线,这样它才能将上述路线与其中的文化相匹配。

    通过查询参数传递文化或更改路由内参数的顺序不是一种选择。

    两个网址 api/en-us/products正如我们 api/products应该路由到同一个 Controller ,前者不会改变文化。

    确定文化的顺序应该是
  • 如果在 url 中定义,则取
  • 如果未在 url 中定义,请检查查询字符串并使用该
  • 如果未在查询中定义,请检查 cookie
  • 如果未在 cookie 中定义,请使用 Accept-Language标题。

  • 2-4 通过 UseRequestLocalization 完成这有效。此外,我不喜欢当前的方法必须为每个 Controller 添加两个属性( {culture} 路由和 [ServiceFilter(typeof(LanguageActionFilter))] )。

    编辑:
    我还想将有效语言环境的数量限制为 SupportedCultures 中的一组。 RequestLocalizationOptions 的属性(property)传递给 UseRequestLocalization .
    IOptions<RequestLocalizationOptions> localizationOptionsLanguageActionFilter上面不起作用,因为它返回了 RequestLocalizationOptions 的新实例哪里 SupportedCultures总是 null而不是传递给的那个。

    FWIW 它是一个 RESTful WebApi 项目。

    最佳答案

    更新 ASP.Net Core 1.1

    全新 RouteDataRequestCultureProvider将作为 1.1 release 的一部分推出,希望这意味着您不必再创建自己的请求提供程序。您可能仍然会发现此处的信息很有用(例如路由位),或者您可能对创建自己的请求文化提供程序感兴趣。

    您可以创建 2 条路由,让您可以在 url 中有和没有文化段的情况下访问端点。两者 /api/en-EN/home/api/home将被路由到家庭 Controller 。 (因此 /api/blah/home 不会将路由与文化匹配,并且会得到 404,因为 blah Controller 不存在)

    为了使这些路由起作用,包含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?}");

    });

    上述路由适用于 MVC 风格的 Controller ,但如果您正在使用 wb api 风格的 Controller 构建休息界面,则属性路由是 MVC 6 中的首选方式。
  • 一种选择是使用属性路由,但如果您可以设置 url 的基段,请为所有 api Controller 使用基类:

    [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" });
    }
    }
  • 在不需要太多自定义代码的情况下避免基类的一种快速方法是通过 web api compatibility shim :
  • 添加包"Microsoft.AspNet.Mvc.WebApiCompatShim": "6.0.0-rc1-final"
  • 添加垫片约定:

    services.AddMvc().AddWebApiConventions();
  • 确保您的 Controller 继承自 ApiController ,这是由 shim 包
  • 添加的
  • 使用 te MapApiRoute 重载定义包含culture 参数的路由:

    routes.MapWebApiRoute("apiLanguage", 
    "api/{language:regex(^[a-z]{{2}}-[A-Z]{{2}}$)}/{controller}/{id?}");

    routes.MapWebApiRoute("DefaultApi",
    "api/{controller}/{id?}");
  • 更干净、更好的选择是创建和应用您自己的 IApplicationModelConvention它负责将文化前缀添加到您的属性路由。这超出了这个问题的范围,但我已经实现了这个想法 localization article

  • 然后你需要新建一个 IRequestCultureProvider它将查看请求 url 并从那里提取文化(如果提供)。

    Once you upgrade to ASP .Net Core 1.1 you might avoid manually parsing the request url and extract the culture segment.

    I have checked the implementation of RouteDataRequestCultureProvider in ASP.Net Core 1.1, and they use an HttpContext extension method GetRouteValue(string) for getting url segments inside the request provider:

    culture = httpContext.GetRouteValue(RouteDataStringKey)?.ToString();

    However I suspect (I haven't had a chance to try it yet) that this would only work when adding middleware as MVC filters. That way your middleware runs after the Routing middleware, which is the one adding the IRoutingFeature into the HttpContext. As a quick test, adding the following middleware before UseMvc will get you no route data:

    app.Use(async (context, next) =>
    {
    //always null
    var routeData = context.GetRouteData();
    await next();
    });


    为了实现新的 IRequestCultureProvider你只需要:
  • 在请求url路径中搜索culture参数。
  • 如果没有找到参数,则返回 null。 (如果所有提供程序都返回 null,则将使用默认区域性)
  • 如果找到文化参数,则返回具有该文化的新 ProviderCultureResult。
  • localization middleware如果它不是受支持的文化之一,则将回退到默认值。

  • 实现将如下所示:

    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));
    }
    }

    最后启用本地化功能,包括您的新提供商作为支持的提供商列表中的第一个。由于它们按顺序进行评估并且第一个返回非空结果的结果获胜,您的提供者将优先,下一个将是 the default ones (查询字符串、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"));

    关于routes - 可选择通过 ASP.NET Core 1.0 应用程序中的 url/route 覆盖请求区域性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35829426/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com