事务未传递给WCF服务

时间:2013-02-12 18:08:45

标签: wcf transactions

我有一个WCF服务,我正在尝试进行事务处理。当我使用事务调用服务时,事务没有被使用,如果我回滚事务,我的数据库更新仍然会发生。

这是服务接口(我只包括我一直在测试的单一方法:

[ServiceContract(SessionMode=SessionMode.Required)]
public interface IUserMenuPermissionService 
{
    [OperationContract]
    [WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
    [TransactionFlow(TransactionFlowOption.Allowed)]
    void InsertUserMenuPermission(string userId, string menuId, int permission);
}

服务实施是:

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class UserMenuPermissionService : IUserMenuPermissionService
{
    private static IUserMenuPermissionProvider _provider = new CoreDataFactory().GetUserMenuPermissionProvider();
    [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = false)]
    public void InsertUserMenuPermission(string userId, string menuId, int permission)
    {
        _provider.InsertUserMenuPermission(userId, menuId, permission);
    }
}

实际的基础提供商没有直接对交易做任何事情,但在这一点上,这不是我的问题,稍后会变得清晰。

WCF的app.config有:

  <bindings>
      <wsHttpBinding>
          <binding name="TransactionBinding" transactionFlow="True" >
          </binding>
      </wsHttpBinding>
  </bindings>

  ...
  ...

  <service name="GEMS.Core.WCFService.UserMenuPermissionService">
    <endpoint address=""  bindingConfiguration="TransactionBinding" binding="wsHttpBinding" contract="SvcProvider.Core.WCFService.IUserMenuPermissionService">
      <identity>
        <dns value="localhost" />
      </identity>
    </endpoint>
    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
    <host>
      <baseAddresses>
        <add baseAddress="http://localhost/SvcProvider.WebService/SvcProvider.Core.WCFService/UserMenuPermissionService/" />
      </baseAddresses>
    </host>
  </service>

客户端是ASP.NET MVC Web应用程序。它的网络配置有:

        <wsHttpBinding>
            <binding name="TransactionBinding" transactionFlow="true" />
        </wsHttpBinding>

        ....
        ....

        <endpoint address="http://localhost/GEMS.WebService/SvcProvider.Core.WCFService.UserMenuPermissionService.svc"
            binding="wsHttpBinding" bindingConfiguration="TransactionBinding"
            contract="UserMenuPermissionService.IUserMenuPermissionService"
            name="WsHttpBinding_IUserMenuPermissionService" />

当我从客户端调用Web服务时,我在事务范围内执行此操作。如果我查看System.Transactions.Transaction.Current,它将被设置为有效的System.Transactions.Transaction,并且它设置了一个DistributedIdentifier。

但是,当我在WCF服务中时,System.Transactions.Transaction.Current设置为null。

所以看来我的交易没有传递给服务。我希望交易是可选的,但是当有交易时,显然我希望它被使用。

我错过了一步吗?

更新

根据BNL的评论,我现在已经使TransactionScopeRequired = true(上面的更新代码反映了这一点)。

如果我在客户端调用没有事务范围的方法,它们似乎运行得很好(我假设服务创建了一个事务)。

如果我在客户端上创建一个事务范围并尝试调用该方法,那么我第一次尝试调用它时,它会挂起大约55秒然后我得到一个事务中止异常。我将事务的超时设置为3分钟(因为默认值为1分钟),但这仍然持续发生在大约55秒。延迟似乎是在客户端,因为在WCF服务实际被调用之前调用自动生成的客户端代理方法55秒。后续呼叫没有55秒延迟。代码如下:

using (TransactionScope ts = new TransactionScope(TransactionScopeOption.RequiresNew, new TimeSpan(0, 3, 0)))
{
    _userMenuPermissionManager.SetPermissions(clientCode, menuPermissions);
    ts.Complete();
}

异常发生在处理中,而不是在ts.Complete()调用中。

at System.Transactions.TransactionStatePromotedAborted.PromotedTransactionOutcome(InternalTransaction tx)
at System.Transactions.TransactionStatePromotedEnded.EndCommit(InternalTransaction tx)
at System.Transactions.CommittableTransaction.Commit()
at System.Transactions.TransactionScope.InternalDispose()
at System.Transactions.TransactionScope.Dispose()
at WebApp.Controllers.AdminController.SetUserMenuPermissions(String clientCode, MenuPermission[] permissions) in Controllers\\AdminController.cs:line 160

正在调用该服务,并且正在将事务传递给它。根据服务跟踪日志,没有错误。一切似乎都很顺利,但最后,它从客户端收到了中止,我想回滚交易。

客户服务日志显示没有异常可以解释55秒的延迟。

所以,虽然我还有点进一步(感谢BNL),但我还是不完全在那里。

更新2

我补充说:

[ServiceBehavior(TransactionTimeout = "00:03:00", InstanceContextMode = InstanceContextMode.PerSession)]

到服务实现并且55秒延迟变为2分55秒延迟,所以看起来事务超时然后服务方法被调用(使用事务)并且服务完成所有东西,然后客户端最后发送一个中止。单独的TransactionScopes后续调用立即中止...

更新3

看来超时是由我错过的早期调用引起的,这是在显式事务中没有发生的,并且因为我没有自动提交事务,所以它因为有未提交的事务而挂起。我现在把所有的电话都包裹在交易中。第一个电话现在立即中止。但是在服务或客户端跟踪日志中仍然没有任何问题的迹象。没有内在的例外,没有。只是一个中止...

更新4

除了BNL的回答,显然使用TransactionAutoComplete = false是不好的。除此之外,我无法真正说明为什么会出现问题,但将其设置为true可修复我的问题,并且仍然允许客户端正确提交或回滚交易(我的印象是{{1}不是这种情况}

1 个答案:

答案 0 :(得分:2)

在第二个代码块中,您有TransactionScopeRequired = false

如果您查看本文档的“备注”部分,您可以确定您没有交易。

http://msdn.microsoft.com/en-us/library/system.servicemodel.operationbehaviorattribute.transactionscoperequired.aspx

  

TransactionScopeRequired = false

     

Binding允许transaction flow = true

     

来电流动交易=真

     

Result =方法在没有事务的情况下执行。

奇怪的是,未指定的是如果前两列都为真但客户端不流动事务会发生什么。看起来该服务将创建一个新的交易,但我不是百分之百确定。