即使出现第二次服务错误,TransactionScope 也允许部分更新

发布于 2024-08-12 10:28:26 字数 2417 浏览 2 评论 0原文

我对相关问题进行了很好的搜索并找到了实施建议,但我仍然对 .NET TransactionScope 存在问题。

我从一个方法调用两个 WCF 服务,即使第二个服务错误(在本例中是故意的),第一个服务也不会回滚。我创建了一个简单的测试应用程序来演示该问题。

下面是调用方法:

private void TryATransaction()
{
    ServiceReference1.IService1 service = new ServiceReference1.Service1Client();
    ServiceReference2.IService1 service2 = new ServiceReference2.Service1Client();

    using (TransactionScope scope = new TransactionScope())
    {
        service.TestMethod("one");
        service2.UpdateSomethingElse("two");

        scope.Complete();
    }
}

第一个服务如下所示(匿名连接):

public bool TestMethod(string anything)
{
        using (TransactionScope scope = new TransactionScope())
        {

            // connect to a db
            using (SqlConnection connection = new SqlConnection("Data Source=DATASOURCE;Initial Catalog=DATABASE;Integrated Security=SSPI;Transaction Binding=Explicit Unbind;"))
            {

                connection.Open();
                // save something
                SqlCommand command1 = new SqlCommand("EXECUTE [DATABASE].[dbo].[uspUpdateCustomer] 3, '[email protected]', 1, null", connection);
                command1.ExecuteNonQuery();
                connection.Close();

            }

            scope.Complete();
        }

    return true;
}

第二个服务与第一个服务相同,只是它更新数据库中的不同字段。

1)如果我运行它而不强制出现错误,它会很好地更新所有字段。

2)当我运行此命令并在第二个服务中强制出错时,第一个服务的更新将提交到数据库,而第二个服务将回滚(错误发生在 ExecuteNonQuery 语句之后)。

此示例代码基本上遵循此处找到的示例: http://msdn.microsoft.com/en-us/ Library/system.transactions.transactionscope.aspx

我添加了显式解除绑定,这是在其他相关问题中推荐的。

非常欢迎您的建议 - 如果需要,我很乐意添加更多信息。

额外信息

分布式标识符似乎始终是 00000000-0000-0000-0000-000000000000 - 我不知道这是否是一个线索。

这是分布式 id 和本地 id 的 dubug 输出(按顺序)

当前交易是 00000000-0000-0000-0000-000000000000 - f6446876-496d-488c-a21c-1e4c4295d50c:8

当前交易是 00000000-0000-0000-0000-000000000000 - 7edd5ba3-7f5a-42af-b9ca-37b3862c26a7:2

当前交易是 00000000-0000-0000-0000-000000000000 - 6fa0e3f7-b655-40ad-8bdd-f0670de79a49:2

事务是通过我的示例应用程序中的 aspx 页面后面的代码启动的。

I have had a good trawl through related questions and implemented suggestions found, but I still have a problem with .NET TransactionScope.

I am calling two WCF services from a method and even though the second service errors (deliberately in this case) the first service doesn't roll back. I have created a simple test application to demonstrate the problem.

Here is the calling method:

private void TryATransaction()
{
    ServiceReference1.IService1 service = new ServiceReference1.Service1Client();
    ServiceReference2.IService1 service2 = new ServiceReference2.Service1Client();

    using (TransactionScope scope = new TransactionScope())
    {
        service.TestMethod("one");
        service2.UpdateSomethingElse("two");

        scope.Complete();
    }
}

The first service looks like this (connections made anonymous):

public bool TestMethod(string anything)
{
        using (TransactionScope scope = new TransactionScope())
        {

            // connect to a db
            using (SqlConnection connection = new SqlConnection("Data Source=DATASOURCE;Initial Catalog=DATABASE;Integrated Security=SSPI;Transaction Binding=Explicit Unbind;"))
            {

                connection.Open();
                // save something
                SqlCommand command1 = new SqlCommand("EXECUTE [DATABASE].[dbo].[uspUpdateCustomer] 3, '[email protected]', 1, null", connection);
                command1.ExecuteNonQuery();
                connection.Close();

            }

            scope.Complete();
        }

    return true;
}

And the second service is identical to the first service, except that it updates a different field in the database.

1) If I run this without forcing an error, it updates all fields fine.

2) When I run this and force an error in the second service, the update from the first service gets committed to the database, whereas the second service gets rolled back (the error is AFTER the ExecuteNonQuery statement).

This example code essentially follows the examples found here:
http://msdn.microsoft.com/en-us/library/system.transactions.transactionscope.aspx

And I added Explicit Unbind, which was recommended in other related questions.

Your suggestions are very welcome - and I'm happy to add more information if it's required.

Extra Information

The distributed identifier seems to be 00000000-0000-0000-0000-000000000000 at all times - I don't know if this is a clue.

Here is the dubug output of distributed id and local id (in that order)

Current transaction is
00000000-0000-0000-0000-000000000000 -
f6446876-496d-488c-a21c-1e4c4295d50c:8

Current transaction is
00000000-0000-0000-0000-000000000000 -
7edd5ba3-7f5a-42af-b9ca-37b3862c26a7:2

Current transaction is
00000000-0000-0000-0000-000000000000 -
6fa0e3f7-b655-40ad-8bdd-f0670de79a49:2

The transaction is being started via the code behind an aspx page in my example app.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

所谓喜欢 2024-08-19 10:28:26

编辑:抱歉,事情倒退了。

该问题很可能是由于将事务与 WCF 一起使用造成的。

请查看这篇有关事务服务的文章。特别是有关客户端/服务模式事务的部分。

基本上,您需要:

  • 在 OperationContract 接口方法上设置 [TransactionFlow(TransactionFlowOption.Mandatory)] 属性
  • 在其实现上设置 [OperationBehavior(TransactionScopeRequired = true)] 属性
  • 添加 将TransactionFlowBindingElement 添加到服务的 BindingContext
  • 从服务的实现中删除 TransactionScope,因为您正在使用客户端的 TransactionScope。

每个成功完成的服务方法都会投票决定事务是否成功(当您使用默认的 TransactionAutoComplete=true OperationBehavior 时)。

如果服务方法由于异常而失败,它会投票决定事务失败。

Edit: sorry had things backwards.

Most likely the issue is due to using Transactions together with WCF.

Check out this article on Transactional Services. In particular the part on Client/Service mode transactions.

Basically you need to:

  • Set the [TransactionFlow(TransactionFlowOption.Mandatory)] attribute on your OperationContract interface methods
  • Set the [OperationBehavior(TransactionScopeRequired = true)] attribute on their implementation
  • Add the TransactionFlowBindingElement to the BindingContext of your service
  • Remove the TransactionScope from your service's implementation, since you're using the client's TransactionScope.

Each service method that completes successfully votes for the transaction to succeed (when you are using the default TransactionAutoComplete=true OperationBehavior).

If a service method fails due to an exception, it votes for the transaction to fail.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文