I have a web application and I make use of a lot of async operations using async/await. Everything worked fine, but when I created custom tasks to run multiple things in parallel, I noticed, that within this task the current culture changes after an await. The problem seems to be, that the threadpool uses the culture of the operation system, which is different from the culture of the request and that the default synchronization does not updates the culture, even when changing the culture of the current thread within the task.
So I create a custom synchronization context:
public sealed class CulturePreservingSynchronizationContext : SynchronizationContext
{
private CultureInfo culture;
private CultureInfo cultureUI;
public CulturePreservingSynchronizationContext()
{
GetCulture();
}
public void MakeCurrent()
{
SetCulture();
SynchronizationContext.SetSynchronizationContext(CreateCopy());
}
public override SynchronizationContext CreateCopy()
{
CulturePreservingSynchronizationContext clonedContext = new CulturePreservingSynchronizationContext();
clonedContext.culture = culture;
clonedContext.cultureUI = cultureUI;
return clonedContext;
}
public override void Post(SendOrPostCallback d, object state)
{
base.Post(s =>
{
SetCulture();
d(s);
}, state);
}
public override void OperationStarted()
{
GetCulture();
base.OperationStarted();
}
private void SetCulture()
{
Thread.CurrentThread.CurrentCulture = culture;
Thread.CurrentThread.CurrentUICulture = cultureUI;
}
private void GetCulture()
{
culture = CultureInfo.CurrentCulture;
cultureUI = CultureInfo.CurrentUICulture;
}
}
You can use it like this. In my simple example it works fine, but I have no real understanding of the very details to evaluate my approach (btw: my os-culture is de-DE). Please note that this is just an example and has nothing to do with the real code. I have just written this to demonstrate that the culture after the await is different to the culture before the await.
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
CulturePreservingSyncContext context = new CulturePreservingSyncContext();
Task.Run(async () =>
{
context.MakeCurrent();
Console.WriteLine(CultureInfo.CurrentCulture);
WebClient client = new WebClient();
string s = await client.DownloadStringTaskAsync(new Uri("http://www.google.de"));
Console.WriteLine(CultureInfo.CurrentCulture);
}).Wait();
Any advice is really welcome to understand if the implementation of the synchronization-context is good or not and if not, if there are any better solutions. I do not want to open a discussion if async and await or tasks are good or not in my situation.
when I created custom tasks to run multiple things in parallel
It's important to distinguish between concurrent (doing multiple things at the same time) and parallel (using multiple threads to do multiple CPU-bound operations at the same time).
I noticed, that within this task the current culture changes after an await.
If you're doing parallel code (i.e., Parallel
or Task.Run
), then your operations should be CPU-bound, and they shouldn't contain an await
at all.
It's a good idea to avoid parallel code on the server. Task.Run
on ASP.NET is almost always a mistake.
Your example code is doing asynchronous work (DownloadStringTaskAsync
) in a background thread (Task.Run
) and synchronously blocking on it (Wait
). That doesn't make any sense.
If you have asynchronous work to do, then you can just use async
-ready primitives such as Task.WhenAll
. The following code will preserve culture when run on ASP.NET, and will perform three downloads simultaneously:
private async Task TestCultureAsync()
{
Debug.WriteLine(CultureInfo.CurrentCulture);
WebClient client = new WebClient();
string s = await client.DownloadStringTaskAsync(new Uri("http://www.google.de"));
Debug.WriteLine(CultureInfo.CurrentCulture);
}
var task1 = TestCultureAsync();
var task2 = TestCultureAsync();
var task3 = TestCultureAsync();
await Task.WhenAll(task1, task2, task3);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With