ContinueWith丢失SynchronizationContext

use*_*702 3 c# asp.net asp.net-mvc async-await c#-5.0

在下面的片段中,SynchronizationContext丢失了,因为那也是CurrentCultureCurrentUICulture.Log()来自这个答案.

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);
}
Run Code Online (Sandbox Code Playgroud)

这是输出:

在GetAsync之前; thread:56,context:AspNetSynchronizationContext,culture:nl,uiculture:nl
ContinueWith; 线程:46,上下文:,文化:nl-BE,uiculture:en-US

在此之前GetAsync,文化和UI文化具有我设定的价值观Application_BeginRequest.在内部ContinueWith,缺少上下文,文化被设置为浏览器提供的内容,并且UI文化被设置为某些默认值.

根据我的理解,一切都AspNetSynchronizationContext应该自动发生.我的代码出了什么问题?

Gus*_*dor 6

为了强制在请求上下文线程上调度continuation,您需要指定TaskScheduler在调度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();
}
Run Code Online (Sandbox Code Playgroud)

不管怎样,你正在使用await它自动编组当前的延续SynchronizationContext.你应该能够做到这一点:

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();
    }
Run Code Online (Sandbox Code Playgroud)