【问题标题】:How can I implement WCF Transaction support on custom class using CoreService?如何使用 CoreService 在自定义类上实现 WCF 事务支持?
【发布时间】:2012-09-13 00:55:07
【问题描述】:

我编写了一个类来帮助使用核心服务向发布目标添加和删除目标。目的地通常通过核心服务作为字符串(带有 XML 内容)公开,所以我围绕它编写了自己的包装器,等等。

我现在遇到需要更新 2 个发布目标的情况,我认为使用事务范围确保两个目标同时更新会很酷。

然而,我正在努力实现这一点。

代码工作(使用标准 CoreService WCF 客户端):

TransactionOptions txOptions = new TransactionOptions 
                    { IsolationLevel = IsolationLevel.ReadCommitted };
using(TransactionScope scope = new TransactionScope(
                            TransactionScopeOption.Required, txOptions))
{
    PublicationTargetData publicationTarget1 = (PublicationTargetData)client.Read("tcm:0-1-65537", readOptions);
    PublicationTargetData publicationTarget2 = (PublicationTargetData)client.Read("tcm:0-2-65537", readOptions);

    publicationTarget1.TargetLanguage = "JSP";
    publicationTarget2.TargetLanguage = "JSP";
    client.Save(publicationTarget1, readOptions);
    client.Save(publicationTarget2, readOptions);

    // Stop saving
    scope.Dispose();
}

执行此代码将成功回滚我所做的更改(如果我在 scope.Dispose() 之前中断并检查 Tridion 中的发布目标,它会成功更改目标,然后“撤消”更改)。

如果我现在尝试在事务中使用我的“扩展发布目标”类,我将无法处理它。

TransactionOptions options = new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted };
using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, options))
{
    ExtendedPublicationTarget target1 = new ExtendedPublicationTarget("tcm:0-1-65537");
    ExtendedPublicationTarget target2 = new ExtendedPublicationTarget("tcm:0-2-65537");
    target1.Destinations.Add(target1.Destinations[0]);
    target2.Destinations.Add(target2.Destinations[0]);
    target1.Save();
    target2.Save();
    scope.Dispose();
}

所以基本上,这是一个问题:我必须做些什么来为我的 .Save() 方法添加事务性?

我试过这样做:

[OperationContract]
[TransactionFlow(TransactionFlowOption.Allowed)]
public void Save()
{
    _client.Save(targetData, readOptions);
}

但这并没有什么不同。有没有办法确定我当前是否正在进行交易并以某种方式“使用”该交易?我不想要求交易,只想有一个操作的选项。

谢谢,很抱歉发了这么长的帖子……想确保我提供了尽可能多的信息。

【问题讨论】:

  • 由于using 子句中有scope 变量,因此不应显式调用Dispose。相反,它会在 using 块结束时自动释放。
  • 你说“我不能处理它”。那是什么意思?你得到一个编译器错误吗?例外?还是代码只是不更新​​您的目标? (PS:如果 WCF 事务根据我习惯的方式命名,则 TransactionScope 将“捎带”现有事务或开始新事务。但由于我没有 WCF 事务的经验,我宁愿见其他人确认/纠正该假设)。
  • 嘿弗兰克,我正试图让它失败,因此我的 scope.Dispose() 调用。在第一个示例中,它正确失败,而在第二个示例中则没有。只是想弄清楚我需要在课堂上添加什么才能使其正常工作......

标签: wcf tridion transactionscope


【解决方案1】:

最好的资源是:WCF Transaction Propagation

您至少缺少一个步骤。您还需要在绑定中启用事务:

<bindings>
   <netTcpBinding>
      <binding name = “TransactionalTCP” transactionFlow = “true” />
   </netTcpBinding>
</bindings>

有没有办法确定我目前是否在进行交易并且 以某种方式“使用”该交易?

是的。要确定您是否处于事务中,您可以检查 Transaction.Current。如果您正在进行交易,除非您明确选择退出,否则您将使用它。这就是环境交易的美好/可怕之处。

WCF Transaction Propagation中的图5:

class MyService : IMyContract 
{
   [OperationBehavior(TransactionScopeRequired = true)]   
   public void MyMethod(...)
   {
      Transaction transaction = Transaction.Current;
      Debug.Assert(transaction.TransactionInformation.
                   DistributedIdentifier != Guid.Empty);
   } 
}

如果 Transaction.Current.TransactionInformation.DistributedIdentifier 为空,则事务是本地事务并且没有“流动”。请注意,在TransactionFlowOptions.Allowed 配置中,如果事务无法流动,它会静默失败。所以这确实是检查的唯一方法......并且不流动比您预期的更容易发生。

当我将事务用于生产服务时,我实际上避免了TransactionFlowOptions.Allowed,因为调用者永远无法确定事务是否真正流动。如果部署中出现绑定配置错误,一切都会正常运行,但回滚会失败……这是一个非常难以检测的错误。所以我切换到必需的。然后 调用者 可以确保他们提供的事务实际上是成功传递的。 (如果事务不在TransactionFlowOptions.Required 配置中流动,您将获得异常。)

【讨论】:

  • 太棒了。我已经以编程方式创建了 NetTCP 绑定,并且没有设置 binding.TransactionFlow = true - 这样做之后,一切都按预期工作。非常感谢
猜你喜欢
  • 2011-04-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-03
  • 1970-01-01
  • 2019-12-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多