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

Posted

技术标签:

【中文标题】在操作中为请求的其余部分设置文化【英文标题】:Setting the Culture for the rest of the request in an Action 【发布时间】:2021-05-17 11:59:40 【问题描述】:

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

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

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

但是,到目前为止,我发现为每个请求设置文化的唯一解决方法是使用中间件从 URL 中读取文化。我不希望 URL 中的文化。

我还没有找到方法来做到这一点。这可能以新的异步方式 aspnet 核心工作吗?我正在使用.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 不会做我想做的事情。

谢谢!

【问题讨论】:

这有帮助吗?:docs.microsoft.com/en-us/aspnet/core/fundamentals/… 能否请您添加一些代码说明它是如何为您工作的,并且您希望它是这样的 @KirkLarkin 这就是我用来获取我所拥有的,这是一个中间件选项,它从请求的 URL 中读取文化,然后设置它。我想要的是一种从控制器中的操作设置它的方法。 【参考方案1】:

您可以通过分配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

参考:

https://github.com/joakimriedel/culture-switcher/blob/master/src/CultureSwitcher.cs

【讨论】:

它不起作用:(在我看来,CurrentCulture 和 CurrentUICulture 在 Action 中设置后被重置为默认值。DefaultThreadCurrentCulture 保持正确设置,但在我所在的位置为空设置这个,并且似乎没有任何影响。 您能否在问题中提供更多详细信息?添加一些你所做的代码? 我添加了一些看起来像我想要实现的代码,理想情况下。谢谢。【参考方案2】:

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

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

我之前没有注意到的一点(我对 .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 方法中设置请求本地化选项来解决此限制。

我为 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 有点猜测。

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

【讨论】:

以上是关于在操作中为请求的其余部分设置文化的主要内容,如果未能解决你的问题,请参考以下文章

如何在 UITableView 中为不同的单元格和标题设置不同的随机颜色?

覆盖 MFC 应用程序的 LoadString

如何在该部分存在时更改该部分的标题标签文本对齐方式

Xilinx ISE FIFO读写操作仿真学习

Vue 组件文本仅部分传递到插槽,其余部分出现在外部 div

在 web.config 中设置的当前文化