I have an ASP.NET MVC 4 application that is targeting .NET Framework 4.7.1, with the problem that the culture is not shared between Controller and View, if the action contains async calls.
I am referencing the NuGet package Microsoft.AspNet.Mvc
5.2.3 (and can be reproduced in 5.2.4).
This is the code in the Controller:
public class CulturesTestController : Controller
{
public async Task<ActionResult> Index(string value)
{
Thread.CurrentThread.CurrentCulture =
CultureInfo.GetCultureInfo("fi-FI");
Thread.CurrentThread.CurrentUICulture =
CultureInfo.GetCultureInfo("fi-FI");
var model = new CulturesContainer
{
CurrentCulture = Thread.CurrentThread.CurrentCulture,
CurrentUICulture = Thread.CurrentThread.CurrentUICulture,
CurrentThreadId = Thread.CurrentThread.ManagedThreadId
};
Log.Write(Level.Info, "CurrentUICulture - Before Await - " +
"CurrentCulture: " +
$"{Thread.CurrentThread.CurrentCulture}, " +
"CurrentUICulture: "
${Thread.CurrentThread.CurrentUICulture} -> "+
"ThreadId: " +
$"{Thread.CurrentThread.ManagedThreadId}");
await GetAwait();
Log.Write(Level.Info, "CurrentUICulture - After Await - " +
"CurrentCulture: " +
$"{Thread.CurrentThread.CurrentCulture}, " +
"CurrentUICulture: " +
$"{Thread.CurrentThread.CurrentUICulture} -> " +
"ThreadId: " +
$"{Thread.CurrentThread.ManagedThreadId}");
return View("Index", model);
}
public class CulturesContainer
{
public CultureInfo CurrentCulture { get; set; }
public int CurrentThreadId { get; set; }
public CultureInfo CurrentUICulture { get; set; }
}
private async Task GetAwait()
{
await Task.Yield();
}
}
And this is the code in View:
@using System.Globalization
@using System.Threading
@model CultureTest.Controllers.CulturesTestController.CulturesContainer
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<title>title</title>
</head>
<body>
<div>
InitialCurrentCulture = {
<label>@Html.Raw(Model.CurrentCulture)</label>
} --
InitialCurrentUICulture = {
<label>@Html.Raw(Model.CurrentUICulture)</label>
} --
InitialThreadId = {
<label>@Html.Raw(Model.CurrentThreadId)</label>
}
<br />
ActualCurrentCulture = {
<label>@Html.Raw(CultureInfo.CurrentCulture)</label>
} --
ActualCurrentUICulture = {
<label>@Html.Raw(CultureInfo.CurrentUICulture)</label>
} --
ActualThreadId = {
<label>@Html.Raw(Thread.CurrentThread.ManagedThreadId)</label>
}
</div>
</body>
</html>
The logs are the following:
20180320-12:04:25.357-12 -INFO -CulturesTestController+<Index>d__0:
CurrentUICulture - Before Await -
CurrentCulture: fi-FI, CurrentUICulture: fi-FI -> ThreadId: 12
20180320-12:04:25.357-8 -INFO -CulturesTestController+<Index>d__0:
CurrentUICulture - After Await -
CurrentCulture: fi-FI, CurrentUICulture: fi-FI -> ThreadId: 8
While the web page shows:
InitialCurrentCulture = { fi-FI } --
InitialCurrentUICulture = { fi-FI } -- InitialThreadId = { 12 }
ActualCurrentCulture = { en-US } --
ActualCurrentUICulture = { en-US } -- ActualThreadId = { 9 }
There was an issue in .NET Framework < 4.6 that was fixed in 4.6, but it seems that the problem still persists in MVC.
If the thread is a thread pool thread that is executing a task-based asynchronous operation and the app targets the .NET Framework 4.6 or a later version of the .NET Framework, its UI culture is determined by the UI culture of the calling thread. (Source https://msdn.microsoft.com/en-us/library/system.globalization.cultureinfo.currentuiculture(v=vs.110).aspx)
Am I not correctly handling the CurrentCulture
, or this is how it is supposed to work? I couldn't find any post related to this issue, for .NET Framework 4.x.