如何修改 Blazor(服务器)中的当前文化日期格式?

Posted

技术标签:

【中文标题】如何修改 Blazor(服务器)中的当前文化日期格式?【英文标题】:How to modify the current culture date format in Blazor (server)? 【发布时间】:2020-06-29 08:41:18 【问题描述】:

ASP.NET Core Blazor globalization and localization 状态:

Blazor 的 @bind 功能根据用户当前的文化执行格式并解析值以进行显示。 可以从System.Globalization.CultureInfo.CurrentCulture property 访问当前文化。

这句话是对的,但问题是,必须在使用之前设置文化(或者可能每次刷新 DOM 时)。

为了演示,我将使用标准的 blazor 计数器应用程序。我们修改Counter.razor

@page "/counter"
@using System.Globalization;

<h1>Counter</h1>
<input type="text" @bind="currentDate" />

<p>Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code 
    private DateTime currentDate = DateTime.Now;
    private int currentCount = 0;

    private void IncrementCount() 
        if (currentCount < 2) Utils.SetCCDateFormat();
        currentCount++;
    

    public class Utils 
        public static void SetCCDateFormat() 
            var cc = CultureInfo.CurrentCulture.Clone() as CultureInfo;
            cc.DateTimeFormat.ShortDatePattern = "dd-yyyy-m";
            CultureInfo.CurrentCulture = cc;
            CultureInfo.CurrentUICulture = cc;
        
    

 

结果是:

当页面首次呈现时,文本框包含格式化的日期 服务器默认文化。 第一次和第二次按下按钮时,日期格式为dd-yyyy-m

我尝试修改OnAfterRenderOnInitialized 中的日期,但没有成功。我发现,唯一可用的解决方案是在剃刀标记的乞求上设置格式。

@Utils.SetCCDateFormat();

有没有办法修改 CurrentCulture 以在 blazor 电路中持久化?

观察到的行为是正确的还是错误?

编辑

到目前为止我发现了什么

可以在中间件中设置区域性属性 (CultureInfo.CurrentCulture),创建 blazor 端点并且更改在电路生命周期内保持不变。当我们在组件生命周期方法中修改CurrentCulture 时,更改只是暂时的(直到方法结束)。

我对问题的理解是

创建电路后,它会将当前文化存储在某处 服务器的线程数有限 在需要时将线程分配给电路,并且当前区域性由开始时存储的内容设置 可以修改CurrentCulture,但这不会影响设置存储,因此当调用另一个事件方法(其他线程)时,将使用原始文化。

所以看来问题是:已经创建好的电路文化设置如何修改?

也许这是不可能的,有必要进行完全刷新(使用导航再次启动请求)并使用中间件来设置修改后的文化。文化储存存在只是我的猜想,我没有任何参考来支持它。

非常感谢 Tyeth 和 Ashiquzzaman 的帮助,但我不会将他们的尝试作为答案。

【问题讨论】:

你检查过这个githubissue吗? @PavelAnikhouski:我知道 blazor webassembly (mono) 中的当前文化存在问题。我认为(希望),blazor 服务器的情况有所不同。 IvanH,您需要澄清您对线程生命周期的理解以及每个线程文化是如何初始化的,或者只是接受中间件是标准设计并满足您的要求,除非您想随心所欲地随机调整线程文化.或者意识到问题不是“如何修改已经创建的电路文化设置?”但实际上如何根据您的需要修改最初为每个用户/请求/线程创建的文化 @Tyeth:我现在知道中间件在文化初始设置中的能力。现在看来,我的现实世界问题可以通过中间件来解决。但我的问题是关于日期格式修改。我个人觉得初始设置(中间件 - 一次)和修改(生命周期方法 - 重复)之间的区别。 感谢您的澄清。我想我心中的问题是您是否需要修改单个用例(页面/控件)的显示/解析,在这种情况下只需使用 string.format 就地格式化,否则您是否要求创建自定义文化以本质上更改日期格式。无论哪种方式,我自己仍然会在登录/首次访问时设置自定义文化,或者在登录时选择正常文化,然后选择字符串格式或 date.parse 以找到一个不同的地方(最后使用自定义模型绑定器?) 【参考方案1】:

1) 使用middleware

示例:

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    
      //your Code
        app.Use(async (context, next) =>
        
            var culture = CultureInfo.CurrentCulture.Clone() as CultureInfo;// Set user culture here
            culture.DateTimeFormat.ShortDatePattern = "dd-yyyy-m";
            CultureInfo.CurrentCulture = culture;
            CultureInfo.CurrentUICulture = culture;

            // Call the next delegate/middleware in the pipeline
            await next();
        );
      //your Code
    

2) 带有服务的自定义中间件:

服务:

public interface ICultureService

    void SetCCDateFormat();

public class CultureService : ICultureService

    public void SetCCDateFormat()
    
        CultureInfo culture = (CultureInfo)CultureInfo.CurrentCulture.Clone();
        culture.DateTimeFormat.ShortDatePattern = "dd-yyyy-m";
        CultureInfo.CurrentCulture = culture;
        CultureInfo.CurrentUICulture = culture;
    

中间件:

public class CultureMiddleware

    private readonly RequestDelegate _next;

    public CultureMiddleware(RequestDelegate next)
    
        _next = next;

    

    public Task Invoke(HttpContext context, ICultureService culture)
               
        culture.SetCCDateFormat();
        return this._next(context);
    

启动:

    public void ConfigureServices(IServiceCollection services)
    
        //Your Code
        services.AddScoped<ICultureService, CultureService>();
        //Your Code
    
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    
        //Your Code
        app.UseMiddleware<CultureMiddleware>();
        //Your Code
    

Culture.razor:

@page "/culture"
@inject ICultureService CultureService
<h1>Counter</h1>
<input type="text" @bind="currentDate" />

<p>Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code 
    private DateTime currentDate = DateTime.Now;
    private int currentCount = 0;

    private void IncrementCount()
    
         if (currentCount < 2) CultureService.SetCCDateFormat();
        currentCount++;
    

3) 如果您可以更改应用程序的默认文化,请使用localization Middleware。 Blazor Server 应用正在为 Localization & Globalization 使用本地化中间件。请求的当前文化在localization Middleware 中设置。本地化中间件在Startup.Configure 方法中启用。必须在任何可能检查请求文化的中间件之前配置本地化中间件(例如,app.UseMvcWithDefaultRoute())。

示例:

var culture = new CultureInfo("en-US");
            culture.DateTimeFormat.ShortDatePattern = "dd-yyyy-MM";
            var supportedCultures = new List<CultureInfo>  culture ;
        app.UseRequestLocalization(new RequestLocalizationOptions
        
            DefaultRequestCulture = new RequestCulture(culture, culture),
            // Formatting numbers, dates, etc.
            SupportedCultures = supportedCultures,
            // UI strings that we have localized.
            SupportedUICultures = supportedCultures
        );

【讨论】:

可以使用中间件在创建电路之前设置文化。这个问题看起来回答了如何修改当前文化(当电路已经创建时)。 DefaultThreadCurrentCulture 修改服务器上所有线程的文化(注意具有数千个用户的多用户环境)。时区问题与 webassembly 相关(并在原始帖子评论中提到)。请您删除不再相关的 cmets(以保持问题干净)? 中间件设置初始文化。不修改当前的。 我已将此答案奖励为最有帮助的,但我仍在寻找可以接受的答案。 @IvanH 谢谢。但现在我认为选项 2 可以满足您的要求。你有完全的控制权。为您服务中的任何位置填充数据。【参考方案2】:

Ashiquzzaman 回答的第二部分(在 OR 之后)暗示了正确的路径。

内置的 ASP.Net Core 本地化中间件将是您最好的新朋友: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/localization?view=aspnetcore-3.1#localization-middleware

您可以依赖默认包含的 CookieRequestCultureProvider,并通过为每个用户设置登录用户的 cookie(我建议您在登录时访问用户存储的首选项),您可以覆盖默认浏览器请求的语言(或系统默认作为最后的手段)。

RequestLocalizationProviders 的列出顺序在发布的链接上,并建议查询字符串可以覆盖可以覆盖浏览器首选项的 cookie:

https://docs.microsoft.com/en-us/aspnet/core/fundamentals/localization?view=aspnetcore-3.1#cookierequestcultureprovider

    QueryStringRequestCultureProvider CookieRequestCultureProvider ** AcceptLanguageHeaderRequestCultureProvider

CookieRequestCultureProvider DefaultCookieName 返回用于跟踪用户首选文化信息的默认 cookie 名称。默认 cookie 名称是 .AspNetCore.Culture。

cookie格式为c=%LANGCODE%|uic=%LANGCODE%,其中c为Culture,uic为UICulture,例如:

c=en-UK|uic=en-US

您绝对应该阅读 Ashiquzzaman 建议的关于全球化和本地化的 blazor 部分: https://docs.microsoft.com/en-us/aspnet/core/blazor/globalization-localization?view=aspnetcore-3.1

【讨论】:

问题是关于修改文化(日期格式) - 不设置文化。这就是示例中使用疯狂日期格式的原因。 我读到它尊重服务器文化,直到您使用用户文化进行更新。请阅读 last 链接,注意日期字段使用 Invariant 并检查 github 上的示例项目,您应该会发现(如果您将您的区域 + 浏览器设置为法语)示例站点应该尊重它。如果使用 Blazor 服务器应用程序,还要注意 ASP.Net 服务器端的本地化和全球化链接。您可能希望制作一些中间件来更改某人登录时的文化,只需设置 cookie 就足够了,但您应该始终允许用户轻松更改语言/文化。 这个想法是在这个图中的端点之前有一些东西docs.microsoft.com/en-us/aspnet/core/fundamentals/middleware/…

以上是关于如何修改 Blazor(服务器)中的当前文化日期格式?的主要内容,如果未能解决你的问题,请参考以下文章

如何创建不在当前文化中的 DateTime 对象

如何在 c# blazor 网页中更新实时日期时间

具有斯洛文尼亚文化 (sl-SI) 的日期时间有空格

excel怎么批量修改一格中的日期时间不修改分秒?

如何更改excel中的默认日期格式

如何使用单元格旁边的下拉菜单对当前日期进行单元格更新?