【发布时间】:2014-07-06 05:46:13
【问题描述】:
我有一个类似的方法:
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。因此,我的项目中的 async/await 行为由 Microsoft.Bcl.Async NuGet Package 提供。
我似乎在这个OOB package 或任何其他OOB package 中找不到TransactionScopeAsyncFlowOption。我只是在某个地方想念它吗?
如果不可用,是否有替代方法可以达到相同的结果?也就是说 - 我希望事务范围能够正确完成或回滚,尽管线程之间存在延续。
我在上面的示例中添加了DoSomethingElse,以说明在事务范围内可能会进行多次调用,因此在一次调用中简单地将所有项目传递到数据库并不是一个可行的选择。
如果重要,存储库使用直接 ADO.Net(SqlConnection、SqlCommand 等)写入 SQL Server。
更新 1
我认为我有一个解决方案,涉及从 .Net 4.5.1 获取 System.Transactions.dll 并将其包含在我的项目中。但是,我发现这仅适用于我的开发盒,因为它已经安装了 4.5.1。部署到只有 .Net 4.0 的机器时它不起作用。它只是给了一个MissingMethodException。我正在寻找适用于 .Net 4.0 安装的解决方案。
更新 2
我最初在 2014 年 7 月提出这个问题。.NET Framework 4.0、4.5 和 4.5.1 于 2016 年 1 月到达end of life。因此该问题不再适用,此处仅供历史参考。
【问题讨论】:
-
你可以随时拿the source code,清理一下,自己实现
-
如果可扩展性不是主要因素,您可以引入线程关联like that。
-
@YuvalItzchakov - 是的,我可以看到它是如何在 System.Transactions 中实现的,但我自己实现它需要重写内部私有方法,如
PushScope和PopScope- 这最终需要重写整个组装... -
@Noseratio - 不,它不是 ASP.Net。这是一个自定义的 Windows 服务应用程序。如果您能提供一个答案来说明您为这个最小示例提出的技术,我很感兴趣。我查看了您的其他链接,但我没有建立联系...
-
@Noseratio - 真可惜。不错的尝试,感谢您的测试。我正在考虑几种不同的技术。 1) 操纵 TLS。 2)明确传递交易。 3) 说服客户升级到 4.5.1。我认为#3是最好的路线。 :)
标签: c# .net .net-4.0 async-await transactionscope