不通过ServicedComponent使用分布式事务(译)
COM+或者System.EnterpriseServices最常用的功能就是它对分布式事务的支持,并且自动事务处理模型很容易通过特性 ([Transaction] 和 [AutoComplete])来实现,这是很常用并且很好的做法,但是,你的类需要从ServicedComponent继承,并且 Transaction特性仅仅在类一级有效,同时你还需要将你的组件注册到COM+中。
如果这些看起来很复杂,但你需要的仅仅是需要使用分布式事务而已,而你并不关心其它的COM+功能,这里将为你提供一个解决方案:通过使用System.EnterpriseServices.ServiceDomain来实现对分布事务的支持。
using System;
using System.EnterpriseServices;
namespace SDSample
{
class Class1
{
[MTAThread]
static void Main(string[] args)
{
ServiceConfig config = new ServiceConfig();
config.Transaction = TransactionOption.Required;
ServiceDomain.Enter(config);
try
{
MyTxCode();
ContextUtil.SetComplete();
}
catch(Exception e)
{
// we got an exception
Console.WriteLine(e.Message);
// 我们需要退出事务,对常写COM+组件的人不会陌生
ContextUtil.SetAbort();
}
finally
{
ServiceDomain.Leave();
}
}
// 我的事务代码
static void MyTxCode()
{
Console.WriteLine(ContextUtil.TransactionId);
// Open connection to database 1
// Execute update in database 1
// Open connection to database 2
// Execute update in database 2
}
}
}
当然, 更进一步,你可以创建一个辅助类型, 我们叫它 ESTransactionScope (与Whidbey 中的 System.Transactions.TransactionScope类似) :
using System;
using System.EnterpriseServices;
namespace SDSample2
{
class Class1
{
[MTAThread]
static void Main(string[] args)
{
using( ESTransactionScope ts = new ESTransactionScope())
{
MyTxCode();
// Everything went well, no exception thrown
// so let’s vote for Commit
ts.Complete();
}
}
static void MyTxCode()
{
Console.WriteLine(ContextUtil.TransactionId);
// Open connection to database 1
// Execute update in database 1
// Open connection to database 2
// Execute update in database 2
}
}
// Used to create transactional code blocks
class ESTransactionScope : IDisposable
{
// Dispose must be called to exit the transactional block
public void Dispose()
{
if(!this.Consistent)
{
ContextUtil.SetAbort();
}
ServiceDomain.Leave();
}
// by calling this method, you mark the scope as being consistent
// and ready to for commit
// if the method is never called, upon dispose, the scope will abort the transaction
public void Complete()
{
this.Consistent = true;
}
public ESTransactionScope()
{
EnterTxContext(TransactionOption.Required);
}
public ESTransactionScope(TransactionOption txOption)
{
EnterTxContext(txOption);
}
private void EnterTxContext(TransactionOption txOption)
{
ServiceConfig config = new ServiceConfig();
config.Transaction = txOption;
ServiceDomain.Enter(config);
}
// By default, the scope is inconsistent;
// To Commit the transaction on exit, the Consistent flag
// must be set to true before Dispose is called
private bool Consistent = false;
}
}
注:在.NET Framework 2.0中提供一个System.Transaction的命名空间,其实现原来于上述相同,同样依赖COM+提供的DTC服务