微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在 Action 中为请求的其余部分设置文化

如何解决在 Action 中为请求的其余部分设置文化

我们的应用程序显示发票数据,因此 URL 类似于 https://localhost/Invoices/guid-goes-here

因此在处理此请求的操作中,我检索了发票数据。此数据中包括商店中使用的文化。

显示发票数据(并因此支付发票)是一个单独的 Web 应用程序,我想将用于显示发票的视图文化设置为使用与发票匹配的文化。

但是,到目前为止,我发现的唯一一种根据请求设置文化的解决方法是使用中间件从 URL 读取文化。我不想要 URL 中的文化。

我还没有找到一种方法来做到这一点。这在新的异步方式 aspnet core 工作中可能吗?我正在使用 .Net 5

我想要的:

public class InvoiceController
{
  [Route("{id}"]
  public async Task<IActionResult> Index(Guid id)
  {
    var invoice = await _apiclient.InvoiceAsync(id);

    // Here is what I want to do
    SetCultureto(invoice.Culture);

    // Views and partials should Now all have culture settings for resources
    return View(invoice);
  }
}

但是因为该方法是异步的,并且所有视图都在不同的线程上呈现,所以简单地设置 CurrentCulture 不会做我想要它做的事情。

谢谢!

解决方法

您可以通过分配 CultureInfo 参数直接设置文化,如下所示:

public void SetCulture(CultureInfo cultureInfo)
{
    CultureInfo.CurrentCulture = cultureInfo;
    CultureInfo.CurrentUICulture = cultureInfo;
    CultureInfo.DefaultThreadCurrentCulture = cultureInfo;
}

如果您想恢复到原始文化,请创建一个可以进行切换和恢复的类:

public sealed class CultureSwitcher : IDisposable
{
    private readonly CultureInfo _originalCulture;

    public CultureSwitcher(string culture)
    {
        _originalCulture = CultureInfo.CurrentCulture;
        var cultureInfo = String.IsNullOrEmpty(culture) 
                          ? CultureInfo.CurrentCulture 
                          : new CultureInfo(culture);

        SetCulture(cultureInfo);
    }

    private void SetCulture(CultureInfo cultureInfo)
    {
        CultureInfo.CurrentCulture = cultureInfo;
        CultureInfo.CurrentUICulture = cultureInfo;
        CultureInfo.DefaultThreadCurrentCulture = cultureInfo;
    }

    public void Dispose()
    {
        SetCulture(_originalCulture);
    }
}

并像下面那样使用它:

using(var cs = new CultureSwitcher("en"))
{
    // do what ever in the specified culture...
}
// here it will be reverted back to the original culture

参考:

,

我已经设法得到我想要的结果,但不是我想要的方式。它可能没有应有的强大,但它适用于我的场景。

所以我最终使用了中间件选项。

之前没有引起我注意的事情(我对 .Net Core 还很陌生)是不同的 Startup.cs 方法的方式:

public void ConfigureServices(IServiceCollection services) {}

public void Configure(IApplicationBuilder app,IWebHostEnvironment env)

互动。

我发现的所有例子,建议做这样的事情:

public void ConfigureServices(IServiceCollection services)
{
  services.Configure<RequestLocalizationOptions>(options =>
  {
    options.DefaultRequestCulture = ...;
    options.SupportedCultures = ...;
    options.SupportedUICultures = ...;
    options.RequestCultureProviders.Clear();
    options.RequestCultureProviders.Add(new CustomCultureProvider());
  });
}

public void Configure(IApplicationBuilder app,IWebHostEnvironment env)
{
  app.UseRequestLocalization();
}

然后在提供程序中我实现了这个方法:

public class CustomCultureProvider : RequestCultureProvider
{
    public override Task<ProviderCultureResult> DetermineProviderCultureResult(HttpContext httpContext)
    {
        var match = Regex.Match(httpContext.Request.Path,"\\/[a-zA-Z]{2}-[a-zA-Z]{2}\\/");
        if (!match.Success) return Task.FromResult(default(ProviderCultureResult));

        var culture = match.Value.Substring(1,5);
        return Task.FromResult(new ProviderCultureResult(culture));
    }
}

我的问题是我无法访问 CultureProvider 中的 API。

我已设法通过不在 ConfigureServices 方法中设置 RequestLocalizationOptions 来解决此限制。

我为 IApplicationBuilder 创建了一个扩展方法

    public static void AddCustomCultureProvider(this IApplicationBuilder app)
    {
        var options = new RequestLocalizationOptions()
        {
            DefaultRequestCulture = ...,SupportedCultures = ...,SupportedUICultures = ...
        };
        var httpClient = app.ApplicationServices.GetService<IRestClient>();
        var apiClient = new ApiClient(httpClient);
        options.RequestCultureProviders.Clear();
        options.RequestCultureProviders.Add(new CustomCultureProvider(apiClient));

        app.UseRequestLocalization(options);
    }

现在我可以了

    public void Configure(IApplicationBuilder app,IWebHostEnvironment env)
    {
        app.AddCustomCultureProvider();
    }

对每个请求做什么

public class CustomCultureProvider : RequestCultureProvider
{
    private readonly IApiClient _client;

    public CustomCultureProvider(IApiClient client)
    {
        _client = client;
    }
    public async override Task<ProviderCultureResult> DetermineProviderCultureResult(HttpContext httpContext)
    {
        var urlParts = httpContext.Request.Path.ToString().Split(new []{ '/' },StringSplitOptions.RemoveEmptyEntries);
        var invoiceId = urlParts.FirstOrDefault(p => Guid.TryParse(p,out var invoiceId));
        if (!string.IsNullOrEmpty(invoiceId))
        {
            var invoice = await _client.InvoiceAsync(new Guid(invoiceId));
            return new ProviderCultureResult(invoice.Culture);
        }
        
        return default(ProviderCultureResult);       
    }
}

是的,这有效!从我不喜欢的请求路径中获取 Guid 有点猜测。

我不会将此标记为答案,因为这是一种解决方法,而不是答案。我对如何改进这一点的建议非常开放,当然,我仍在寻找原始问题的答案。但现在我已经准备好了。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。