Async/Await模式中使用TransactionScope时,要设置参数为TransactionScopeAsyncFlowOption.Enabled枚举(转载)
TransactionScope and Async/Await. Be one with the flow!
You might not know this, but the 4.5.0 version of the .NET Framework contains a serious bug regarding System.Transactions.TransactionScope and how it behaves with async/await. Because of this bug, a TransactionScope can't flow through into your asynchronous continuations. This potentially changes the threading context of the transaction, causing exceptions to be thrown when the transaction scope is disposed.
This is a big problem, as it makes writing asynchronous code involving transactions extremely error-prone.
The good news is that as part of the .NET Framework 4.5.1, Microsoft released the fix for that "asynchronous continuation" bug. The thing is that developers like us now need to explicitly opt-in to get this new behavior. Let's take a look at how to do just that.
TL;DR
- If you are using TransactionScope and async/await together, you should really upgrade to .NET 4.5.1 right away.
- A TransactionScope wrapping asynchronous code needs to specify TransactionScopeAsyncFlowOption.Enabled in its constructor.
An explicit transaction means we create a new instance of a CommittableTransaction in code and pass it from method to method as a parameter. Ambient or implicit means we wrap a code inside a TransactionScope. This sets the thread-static property Transaction.Current to a new instance of a CommittableTransaction.
public void TransactionScopeAffectsCurrentTransaction() { Debug.Assert(Transaction.Current == null); using (var tx = new TransactionScope()) { Debug.Assert(Transaction.Current != null); SomeMethodInTheCallStack(); tx.Complete(); } Debug.Assert(Transaction.Current == null); } private static void SomeMethodInTheCallStack() { Debug.Assert(Transaction.Current != null); }
public async Task TransactionScopeWhichDoesntBehaveLikeYouThinkItShould() { using (var tx = new TransactionScope()) { await SomeMethodInTheCallStackAsync() .ConfigureAwait(false); tx.Complete(); } } private static async Task SomeMethodInTheCallStackAsync() { await Task.Delay(500).ConfigureAwait(false); }
Unfortunately, it doesn't work that way. The code almost (but only almost) executes similarly to the synchronous version, but if the project this code is written in targets .NET Framework 4.5, when we reach the end of the using block and try to Dispose the TransactionScope the following exception is thrown:
System.InvalidOperationException : A TransactionScope must be disposed on the same thread that it was created.
To make TransactionScope and async work properly we need to upgrade our project to .NET 4.5.1.
Let it flow
With .NET 4.5.1 the TransactionScope has a new enumeration called TransactionScopeAsyncFlowOption which can be provided in the constructor. You have to explicitly opt-in the transaction flow across thread continuations by specifying TransactionScopeAsyncFlowOption.Enabled like this:
using (var tx = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled)) { await SomeMethodInTheCallStackAsync() .ConfigureAwait(false); tx.Complete(); }
If you were wondering, the default TransactionScopeAsyncFlowOption is Suppress; Microsoft wanted to avoid breaking codebases that assumed the old .NET 4.5.0 behavior.
In the flow
Even if you are not using NServiceBus but TransactionScope combined with async/await you should update all your code paths that are using a TransactionScope to include TransactionScopeAsyncFlowOption.Enabled. This enables the transaction to properly flow into asynchronous code, preventing business logic from misbehaving when used under a TransactionScope. This will save you many headaches.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
2019-02-13 使用自定义端口连接SQL Server的方法(转载)