Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to modify the current culture date format in Blazor (server)?

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 the System.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.

like image 760
IvanH Avatar asked Mar 18 '20 09:03

IvanH


People also ask

How do you set the culture in Blazor?

Use Localization Middleware to set the app's culture. If the app doesn't already support culture selection per the Dynamically set the culture by user preference section of this article: Add localization services to the app with AddLocalization. Specify the app's default and supported cultures in Program.

How do I change my Blazor page?

You can redirect to a page in Blazor using the Navigation Manager's NavigateTo method. In the following code snippet, it will redirect to the home page when this page gets loaded. Similarly, you can call NavigateTo() method from NavigationManager class anywhere to redirect to another page.

How do you change title on Blazor?

Blazor doesn't provide any built-in method to change the page title. This means you need to call a JS function to update the document title. The page title is updated when you set the Title parameter.


1 Answers

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
        });
like image 109
Ashiquzzaman Avatar answered Sep 18 '22 13:09

Ashiquzzaman