提问者:小点点

事务未传递给WCF服务


我有一个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.NETMVCWeb应用程序。它的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. Transaction.Transaction.当前,它被设置为有效的System.Transaction.Transaction并且它具有一个分布式标识符集。

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

所以我的事务似乎没有被传递到服务。我希望事务是可选的,但是当有事务时,显然,我希望它被使用。

我错过了一步吗?

更新

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

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

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

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

异常发生在处置中,而不是在ts.完成()调用中。

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的回答之外,显然使用TransactionAuto完成=false是不好的。除此之外,我不能说为什么会有问题,但是将其设置为true解决了我的问题,并且仍然允许客户端正确提交或回滚事务(我的印象是TransactionAuto完成=true不是这种情况


共1个答案

匿名用户

在您的第二个代码块中,您有TransactionScope必需=false

如果您查看本文档的备注部分,您可以确定您没有事务。

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

事务范围必填=假

绑定允许交易流=true

调用方流转事务=true

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

奇怪的是,没有指定的是,如果前两列都为真,但客户端没有流转事务会发生什么。看起来服务会创建一个新事务,但我不是100%确定。