首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何在.NET 4.0中支持带有Microsoft.Bcl.Async的TransactionScope中的异步方法?

如何在.NET 4.0中支持带有Microsoft.Bcl.Async的TransactionScope中的异步方法?
EN

Stack Overflow用户
提问于 2014-07-06 13:46:13
回答 3查看 12.9K关注 0票数 24

我有一个类似的方法:

代码语言:javascript
复制
public async Task SaveItemsAsync(IEnumerable<MyItem> items)
{
    using (var ts = new TransactionScope())
    {
        foreach (var item in items)
        {
            await _repository.SaveItemAsync(item);
        }

        await _repository.DoSomethingElse();

        ts.Complete();
    }
}

这当然有问题,因为TransactionScope不能很好地处理async/await。

它会失败,并显示InvalidOperationException,并显示以下消息:

“TransactionScope必须放在创建它的同一线程上。”

我在this answer上读到了关于TransactionScopeAsyncFlowOption的文章,这似乎正是我所需要的。

然而,对于这个特定的项目,我有一个硬要求,必须支持.Net 4.0,并且不能升级到4.5或4.5.1。因此,我的项目中的异步/等待行为是由Microsoft.Bcl.Async NuGet Package提供的。

我似乎在这个或任何其他OOB package中找不到TransactionScopeAsyncFlowOption。我是不是错过了什么地方?

如果它不可用,有没有其他方法可以达到同样的效果?也就是说,我希望事务作用域正确地完成或回滚,尽管线程与延续交叉。

我在上面的示例中添加了DoSomethingElse,以说明在事务范围内可能要进行多个调用,因此简单地在一次调用中将所有项传递给数据库不是一个可行的选择。

如果重要,存储库使用直接ADO.Net (SqlConnectionSqlCommand等)来写入SQL Server。

更新1

我想我有一个解决方案,包括从.Net 4.5.1中提取System.Transactions.dll并将其包含在我的项目中。然而,我发现这只适用于我的dev box,因为它已经安装了4.5.1。当部署到只有.Net 4.0的计算机上时,它不起作用。它只是给出了一个MissingMethodException。我正在寻找一种可以在.Net 4.0安装上工作的解决方案。

更新2

我最初问这个问题是在2014年7月。2016年1月,end of life发布了.NET Framework4.0、4.5和4.5.1。因此,这个问题不再适用,这里仅供历史参考。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-11-20 18:28:58

这在.NET Framework4.0中是不可能实现的。此外,.NET Framework 4.0 reached end of life on 2016-01-12,因此不再相关。

要在.NET中的异步方法中支持事务作用域(从.NET框架4.5.1开始),请使用TransactionScopeAsyncFlowOption.Enabled

代码语言:javascript
复制
public static TransactionScope CreateAsyncTransactionScope(IsolationLevel isolationLevel = IsolationLevel.ReadCommitted)
    {
        var transactionOptions = new TransactionOptions
        {
            IsolationLevel = isolationLevel,
            Timeout = TransactionManager.MaximumTimeout
        };
        return new TransactionScope(TransactionScopeOption.Required, transactionOptions, TransactionScopeAsyncFlowOption.Enabled);
    }
票数 31
EN

Stack Overflow用户

发布于 2020-01-10 19:00:37

在框架4.5.1中,TransactionScope在处理异步/等待操作方面得到了修复。不要与4.5一起使用!

使用带有DbContextTransaction的EF6作为替代。

代码语言:javascript
复制
using (Entities entities = new Entities())
    using (DbContextTransaction scope = entities.Database.BeginTransaction())
    {
        entities.Database.ExecuteSqlCommand("SELECT TOP 1 KeyColumn FROM MyTable)");
        scope.Commit();
    }

更多信息

TransactionScope和Async/Await。随波逐流!Daniel Marbach写于2015年8月6日,你可能不知道这一点,但是.NET框架的4.5.0版本包含一个关于System.Transactions.TransactionScope以及它在异步/等待时的行为的严重错误。由于这个bug,TransactionScope不能流入您的异步延续。这可能会更改事务的线程上下文,从而导致在释放事务作用域时引发异常。

这是一个很大的问题,因为它使得编写涉及事务的异步代码非常容易出错。

好消息是,作为.NET框架4.5.1的一部分,微软发布了对“异步延续”错误的修复。问题是,像我们这样的开发人员现在需要显式地选择加入才能获得这种新行为。让我们来看看如何做到这一点。

TL;DR

如果你同时使用TransactionScope和async/await,你真的应该立即升级到.NET 4.5.1。TransactionScope包装异步代码需要在其构造函数中指定TransactionScopeAsyncFlowOption.Enabled。

票数 2
EN

Stack Overflow用户

发布于 2014-08-04 03:18:41

不确定这是否适合您的场景,但可以在ASP.NET应用程序中使用ConfigureAwait(false),以确保等待的函数调用重新进入调用请求上下文。

因此,如果此代码在ASP.NET应用程序中运行,则使用以下代码:

代码语言:javascript
复制
await _repository.SaveItemAsync(item).ConfigureAwait(false);

将确保在请求线程上继续执行。

票数 -3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24593070

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档