即使出现第二次服务错误,TransactionScope 也允许部分更新
我对相关问题进行了很好的搜索并找到了实施建议,但我仍然对 .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:8Current transaction is
00000000-0000-0000-0000-000000000000 -
7edd5ba3-7f5a-42af-b9ca-37b3862c26a7:2Current 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
编辑:抱歉,事情倒退了。
该问题很可能是由于将事务与 WCF 一起使用造成的。
请查看这篇有关事务服务的文章。特别是有关客户端/服务模式事务的部分。
基本上,您需要:
[TransactionFlow(TransactionFlowOption.Mandatory)]
属性[OperationBehavior(TransactionScopeRequired = true)]
属性TransactionFlowBindingElement
添加到服务的 BindingContextTransactionScope
,因为您正在使用客户端的 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:
[TransactionFlow(TransactionFlowOption.Mandatory)]
attribute on your OperationContract interface methods[OperationBehavior(TransactionScopeRequired = true)]
attribute on their implementationTransactionFlowBindingElement
to the BindingContext of your serviceTransactionScope
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.