考虑下面的小程序,它简单地创建一个TransactionScope
prints Transaction.Current
,调用另一个 AppDomain 中的一个方法(执行需要一段时间),然后Transaction.Current
在返回时打印。
using System;
using System.Linq;
using System.Runtime.Remoting.Lifetime;
using System.Threading;
using System.Transactions;
namespace TransactionScopeFlowTest
{
class Program
{
static void Main(string[] args)
{
// These times are just to generate the error faster. Normally the initial lease is 5 minutes, meaning the method call
// would have to take 5 minutes to occur, so we speed it up here for demonstration purposes.
LifetimeServices.LeaseManagerPollTime = TimeSpan.FromSeconds(1);
LifetimeServices.LeaseTime = TimeSpan.FromSeconds(1);
LifetimeServices.RenewOnCallTime = TimeSpan.FromSeconds(1);
AppDomain domain = AppDomain.CreateDomain("Temp", null, AppDomain.CurrentDomain.SetupInformation);
using (TransactionScope scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
Console.WriteLine($"Transaction Before Call = {Transaction.Current?.TransactionInformation?.LocalIdentifier?.ToString() ?? "<null>"}");
domain.DoCallBack(AppDomainCallback);
Console.WriteLine($"Transaction After Call = {Transaction.Current?.TransactionInformation?.LocalIdentifier?.ToString() ?? "<null>"}");
scope.Complete();
}
AppDomain.Unload(domain);
}
public static void AppDomainCallback()
{
Thread.Sleep(3000);
}
}
}
出乎意料的是,该程序生成以下输出:
Transaction Before Call = 1f980219-2583-4796-8d6d-256a6f100698:1
Transaction After Call = <null>
如果我TransactionScopeAsyncFlowOption
将 ctor 中的更改TransactionScope
为TransactionScopeAsyncFlowOption.Suppress
,则事务在调用后仍然存在。
我的怀疑是跨逻辑上下文的事务范围流由 CallContext 处理,它在远程调用中传播,并且使用的键继承MarshalByRefObject
,并且由于它们没有注册 any ISponsor
,代理将在初始租用时间后断开连接。然后,一旦我们从调用返回,逻辑调用上下文就会与原始上下文合并,这意味着事务不再存在。
我正在寻找一种方法来规避这个问题,如果这被认为是.NET 中的一个错误?