如何取消异步处理的TransactionScope /等待? [英] How to dispose TransactionScope in cancelable async/await?

查看:1265
本文介绍了如何取消异步处理的TransactionScope /等待?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图使用新的异步/等待功能异步用DB工作。由于有些要求可能会很长,我希望能够取消它们。我遇到的问题是,的TransactionScope 显然有一个线程亲和力,似乎取消该任务时,它的的Dispose()被运行在一个错误的线程。

I'm trying to use the new async/await feature to asynchronously work with a DB. As some of the requests can be lengthy, I want to be able to cancel them. The issue I'm running into is that TransactionScope apparently has a thread affinity, and it seems that when canceling the task, its Dispose() gets ran on a wrong thread.

特别是,当调用 .TestTx()我得到以下 AggregateException 包含出现InvalidOperationException task.Wait()

Specifically, when calling .TestTx() I get the following AggregateException containing InvalidOperationException on task.Wait ():

"A TransactionScope must be disposed on the same thread that it was created."

这里的code:

Here's the code:

public void TestTx () {
    var cancellation = new CancellationTokenSource ();
    var task = TestTxAsync ( cancellation.Token );
    cancellation.Cancel ();
    task.Wait ();
}

private async Task TestTxAsync ( CancellationToken cancellationToken ) {
    using ( var scope = new TransactionScope () ) {
        using ( var connection = new SqlConnection ( m_ConnectionString ) ) {
            await connection.OpenAsync ( cancellationToken );
            //using ( var command = new SqlCommand ( ... , connection ) ) {
            //  await command.ExecuteReaderAsync ();
            //  ...
            //}
        }
    }
}

更新:注释掉的部分是要表明有事情做了 - 异步 - 有一次,它是开放的连接,但不要求code重现该问题

UPDATED: the commented out part is to show there's something to be done — asynchronously — with the connection once it's open, but that code is not required to reproduce the issue.

推荐答案

这个问题的原因是,我是原型在控制台应用程序中的code,我没有在这个问题反映了茎。

The problem stems from the fact that I was prototyping the code in a console application, which I did not reflect in the question.

办法异步/等待继续执行code后等待取决于 SynchronizationContext.Current <的presence / code>和控制台应用程序还没有一个在默认情况下,这意味着使用当前被执行的延续的TaskScheduler ,这是一个线程池,所以它(的可能?的)执行在不同的线程。

The way async/await continues to execute the code after await is dependent on the presence of SynchronizationContext.Current, and console application don't have one by default, which means the continuation gets executed using the current TaskScheduler, which is a ThreadPool, so it (potentially?) executes on a different thread.

因此​​,人们只是需要有一个的SynchronizationContext ,这将确保的TransactionScope 设置在同一线程创建它。 WinForms和WPF应用都会有它在默认情况下,当控制台应用程序可以使用一个自定义的,或借WPF DispatcherSynchronizationContext

Thus one simply needs to have a SynchronizationContext that will ensure TransactionScope is disposed on the same thread it was created. WinForms and WPF applications will have it by default, while console applications can either use a custom one, or borrow DispatcherSynchronizationContext from WPF.

下面是详细解释力学两个伟大的博客文章:

等待,SynchronizationContext的,和控制台应用

等待,SynchronizationContext的,和控制台程序:第2部分

Here are two great blog posts that explain the mechanics in detail:
Await, SynchronizationContext, and Console Apps
Await, SynchronizationContext, and Console Apps: Part 2

这篇关于如何取消异步处理的TransactionScope /等待?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆