问题
ASP.NET Core Blazor globalization and localization states:
Blazor's
@bind
functionality performs formats and parses values for display based on the user's current culture.
The current culture can be accessed from theSystem.Globalization.CultureInfo.CurrentCulture property
.
The statement is true, but the problem is that, the culture has to be set just before it is used (or maybe each time the DOM is refreshed).
For demonstration I will use standard blazor counter application. Let's modify 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;
}
}
}
The result is:
- when the page is first rendered the text box contain date formatted by server default culture.
- when the button is pressed first and second time the date format is
dd-yyyy-m
I attempted to modify the date in OnAfterRender
, OnInitialized
without success. Only usable solution, I have found, is setting the format on the begging of razor markup.
@{Utils.SetCCDateFormat();}
Is there a way to modify CurrentCulture to become persistent in the blazor circuit?
Is the observed behavior correct or is it a bug?
Edit
What I have found so far
It is possible to set culture properties (CultureInfo.CurrentCulture
) in a middleware before the blazor endpoint is created and the changes are persistent for the circuit lifetime. When we modify CurrentCulture
in component lifecycle methods the change is only temporary (till the end of the method).
My understanding of the problem is
- When a circuit is created it stores the current culture somewhere
- A server has a limited number of threads
- A thread is assigned to a circuit when required and the current culture is set by what was stored at the beginning
- It is possible to modify the
CurrentCulture
, but this doesn't influence the setting storage and so when another event method is called (other thread) the original culture is used.
So it seems that the question is: How to modify the circuit culture settings when it is already created?
Maybe it is not possible and it is necessary do full refresh (start a request again with navigation) and use a middleware to set a modified culture. A culture storage existence is only my conjecture and I don't have any reference to support it.
Many thanks to Tyeth and Ashiquzzaman for help but I am not taking their attempts as the answer.
回答1:
The second part of Ashiquzzaman's answer (after OR) hints at the correct path to take.
The built in ASP.Net Core localisation middleware will be your new best friend: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/localization?view=aspnetcore-3.1#localization-middleware
You can rely on the default included CookieRequestCultureProvider, and by setting a cookie for your logged in users on a per user basis (I suggest upon login as you will have access to the Users stored preferences then) you can override the default browser requested language (or system default as a last resort).
The listed order of RequestLocalizationProviders is on that link posted and suggests the querystring can override the cookie which can override the browser preference:
https://docs.microsoft.com/en-us/aspnet/core/fundamentals/localization?view=aspnetcore-3.1#cookierequestcultureprovider
- QueryStringRequestCultureProvider
- CookieRequestCultureProvider **
- AcceptLanguageHeaderRequestCultureProvider
The CookieRequestCultureProvider DefaultCookieName returns the default cookie name used to track the user's preferred culture information. The default cookie name is .AspNetCore.Culture.
The cookie format is c=%LANGCODE%|uic=%LANGCODE%, where c is Culture and uic is UICulture, for example:
c=en-UK|uic=en-US
You should definitely read the blazor section on globalisation and localisation as suggested by Ashiquzzaman: https://docs.microsoft.com/en-us/aspnet/core/blazor/globalization-localization?view=aspnetcore-3.1
回答2:
1) Use middleware
Example:
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) Custom middleware with service:
Service :
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;
}
}
Middleware:
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);
}
}
Startup:
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) If you can to change default Culture of the application the use localization Middleware. Blazor Server apps are using Localization Middleware for Localization & Globalization. The current culture on a request is set in the localization Middleware. The localization middleware is enabled in the Startup.Configure
method. The localization middleware must be configured before any middleware which might check the request culture (for example, app.UseMvcWithDefaultRoute()
).
Example:
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
});
来源:https://stackoverflow.com/questions/60736406/how-to-modify-the-current-culture-date-format-in-blazor-server