ContinueWith loses the SynchronizationContext

本文关键字:SynchronizationContext the loses ContinueWith | 更新日期: 2023-09-27 17:59:14

在下面的代码段中,SynchronizationContext丢失了,因此CurrentCultureCurrentUICulture也丢失了。CCD_ 4就是来自这个答案。

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);
}

这是输出:

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

GetAsync之前,区域性和UI区域性具有我在Application_BeginRequest中设置的值。在ContinueWith中,上下文丢失,区域性被设置为浏览器提供的内容,UI区域性被设为某些默认值。

据我所知,AspNetSynchronizationContext的一切都应该自动发生。我的代码出了什么问题?

ContinueWith loses the SynchronizationContext

为了在请求上下文线程上强制调度延续,您需要指定在调度延续时应使用的TaskScheduler

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();
}

但是,您使用的是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();
    }

您尝试过TaskContinuationOptions.ExecuteSynchronously吗?它应该在同一个线程中运行延续任务。。。

http://msdn.microsoft.com/en-us/library/vstudio/system.threading.tasks.taskcontinuationoptions

"指定应同步执行延续任务。指定此选项后,延续将在导致先行任务转换到其最终状态的同一线程上运行。如果创建延续时先行任务已经完成,则延续将在创建延续的线程上运行同步执行。"