In the snippet below, the SynchronizationContext is lost, and because of that also the CurrentCulture and CurrentUICulture. Log() comes from this answer.
public async Task<ActionResult> Index()
{
Log("before GetAsync");
await new HttpClient().GetAsync("http://www.example.com/")
.ContinueWith(request =>
{
Log("ContinueWith");
request.Result.EnsureSuccessStatusCode();
}, TaskContinuationOptions.AttachedToParent);
return View();
}
static void Log(string message)
{
var ctx = System.Threading.SynchronizationContext.Current;
System.Diagnostics.Debug.Print("{0}; thread: {1}, context: {2}, culture: {3}, uiculture: {4}",
message,
System.Threading.Thread.CurrentThread.ManagedThreadId,
ctx != null ? ctx.GetType().Name : String.Empty,
System.Threading.Thread.CurrentThread.CurrentCulture.Name,
System.Threading.Thread.CurrentThread.CurrentUICulture.Name);
}
This is the output:
before GetAsync; thread: 56, context: AspNetSynchronizationContext, culture: nl, uiculture: nl
ContinueWith; thread: 46, context: , culture: nl-BE, uiculture: en-US
Before the GetAsync, the culture and UI culture have the values I set in Application_BeginRequest. Inside the ContinueWith, the context is missing, the culture is set to what’s provided by the browser, and UI culture is set to some default.
From what I understand, everything with AspNetSynchronizationContext should be happening automatically. What’s wrong with my code?
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
In order to force scheduling of the continuation on the request context thread, you need to specify the TaskScheduler that should be used when scheduling the continuation.
public async Task<ActionResult> Index()
{
Log("before GetAsync");
await new HttpClient().GetAsync("http://www.example.com/")
.ContinueWith(request =>
{
Log("ContinueWith");
request.Result.EnsureSuccessStatusCode();
},
TaskContinuationOptions.AttachedToParent,
CancellationToken.None,
TaskScheduler.FromCurrentSynchronizationContext());
return View();
}
Howver, you are using await which automatically marshals continuations on to the current SynchronizationContext. You should be able to do this:
public async Task<ActionResult> Index()
{
Log("before GetAsync");
HttpResponseMessage request = await new HttpClient().GetAsync("http://www.example.com/");
//everything below here is you 'continuation' on the request context
Log("ContinueWith");
request.EnsureSuccessStatusCode();
return View();
}
Method 2
Did you try with TaskContinuationOptions.ExecuteSynchronously? It should ran the continuation task in the same thread…
http://msdn.microsoft.com/en-us/library/vstudio/system.threading.tasks.taskcontinuationoptions
“Specifies that the continuation task should be executed synchronously. With this option specified, the continuation will be run on the same thread that causes the antecedent task to transition into its final state. If the antecedent is already complete when the continuation is created, the continuation will run on the thread creating the continuation. Only very short-running continuations should be executed synchronously.”
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0