创建新的TransactionScope()时出现“事务已中止”异常。

3

这是我第一个使用WCF客户端和服务器的项目,涉及到SQL Server 2008。

我被迫在我的Windows窗体应用程序中使用TransactionScope事务来作为客户端访问WCF服务。我之前从未使用过这种类型的事务,通常使用connection.BeginTransaction(),因为可以更容易地跟踪其进展情况。

我调用一个函数(希望该函数嵌套了事务),但其中一个新建TransactionScope实例的调用会出现“事务已中止”的异常。内部异常为空。我认为在此之前事务已经回滚了,但是我不知道如何跟踪当前是否存在正在进行的环境事务以及其状态。

以下是示例客户端代码(非真实代码。我已检查所有函数是否使用了scope.Commit())。 请问如何定位问题?

(经常收到必须启动MSDTC服务的错误消息,我已经启动了该服务,但不理解为什么在只有一个数据库/WCF服务的情况下需要使用分布式)

void Function1(AMessageObj m)
{
  using (var client = GetOpenWebClient())
    WriteMessage(m, client);
}

void WriteMessage(AMessage m, OpenWebClient client)
{
  using (var scope = new TransactionScope())
  {
    var audit = GetSomeAuditInfo(AMessage.UserId, client);
    WriteTheMessage(AMessage, client);
    WriteAudit(audit, client);
    client.SetTime(DateTime.Now);
    scope.Commit();
  }  
}

AuditRecord GetSomeAuditInfo(Int userId, OpenWebClient client)
{
  var result = client.ReadAuditRecord(userId);
  return AuditRecord.FromWeb(result);
}

void WriteTheMessage(AMessage msg, OpenWebClient client)
{
  using (var scope = new TransactionScope())
  {
    client.WriteTheMessage(msg.ToWeb());
    scope.Commit();
  }
}

void WriteAudit(AuditRecord audit, OpenWebClient client)
{
  using (var scope = new TransactionScope())
  {
    client.WriteAudit(audit.ToWeb());
    scope.Commit();
  }
}

例子服务 WCF

[ServiceContract]
interface IService
{
  [OperationContract]
  void WriteTheMessage(WebRecord message);

  [OperationContract]
  WebRecord ReadAuditRecord(int userId);

  [OperationContract]
  void WriteAudit(WebRecord audit);
}

class MyWebService : IService
{
  [OperationBehavior(TransactionScopeRequired = true)]
  void IService.WriteTheMessage(WebRecord record)
  {
    using (var connection = GetOpenConnection())
    {
      dowritethings;
    }
  }

  [OperationBehavior(TransactionScopeRequired = false)]
  WebRecord IService.ReadAuditRecord(WebRecord record)
  {
    using (var connection = GetOpenConnection())
    {
      return readthings;
    }
  }

  [OperationBehavior(TransactionScopeRequired = true)]
  void IService.WriteAudit(WebRecord record)
  {
    using (var connection = GetOpenConnection())
    {
      dowritethings;
    }
  }
}

内部异常为空,您的代码中任何对象在运行时都为空,这将导致空引用异常并自动中止事务。因此,您必须找出哪个对象为空。 - Vimal CK
你能够确定性地重现这个问题吗?还是它是间歇性的,基于竞态条件的? - Eugene Podskal
2个回答

3
我在网上搜索了如何查看环境事务状态,并找到了Transaction.Current属性,我将其放入监视窗口。 这显示在我完全错过的一个外部函数调用后中止了。进入该函数,我发现在创建事务和提交之间调用了return;因此导致了中止。
感谢您的帮助。

1
每个在服务器上打开的连接都是一个分布式实体。偶然情况下,在测试期间您经常从连接池中获取相同的物理连接。这种行为非常糟糕,因为它会导致您在测试期间无法找到问题。这种设置在数据库方面表现出一种不确定性行为。
在任何情况下,您应该在这里使用分布式事务,因为WCF和SQL Server是不同的资源。这应该确定地升级为使用MSDTC。
“我假设在此之前事务已回滚”
很可能如此。使用WCF事务时,您的代码始终设置了环境事务。可能在某个地方有一些异常,而您没有注意到。将调试器设置为在所有异常上中断。使用Fiddler观察发送到网络的响应。也许它们包含某种错误。WCF跟踪是另一种选择。
如果这没有任何结果,请尝试创建可靠的复制。通常,在过程中您自己会发现错误。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接