在TransactionScope中登记System.Web.Providers

时间:2011-10-24 20:55:28

标签: c# transactions asp.net-membership

我们正在尝试使用System.Transactions.TransactionScope将System.Web.Providers成员资格管理集成到一个事务中,并不断收到以下错误消息:

The operation is not valid for the state of the transaction.

使用以下更令人困惑的消息包含在异常中:

The provider did not return a ProviderManifestToken string.

在有人要求之前,是的,我们已经验证连接字符串是正确的,并且我们用于连接到db的用户具有适当的权限。如果我们尝试从TransactionScope块中调用Membership.CreateUser(),它就可以工作。把它放在TransactionScope中就会失败。

关于环球提供商的信息似乎很少。几乎所有你看到的都是NuGet页面的链接和6月份Scott Hanselman的博客文章。

有没有人知道如何让System.Web.Providers参与交易?

感谢。

这是完整的堆栈跟踪,以防它有用:

System.Data.ProviderIncompatibleException was unhandled by user code
  Message=The provider did not return a ProviderManifestToken string.
  Source=System.Data.Entity
  StackTrace:
       at System.Data.Common.DbProviderServices.GetProviderManifestToken(DbConnection connection)
       at System.Web.Providers.Entities.ModelHelper.GetStorageMetadata(String providerName, DbConnection connection, String ssdl)
       at System.Web.Providers.Entities.ModelHelper.CreateMetadataWorkspace(String providerName, DbConnection connection, String csdl, String ssdl, String msl)
       at System.Web.Providers.Entities.ModelHelper.CreateEntityConnection(ConnectionStringSettings setting, String csdl, String ssdl, String msl)
       at System.Web.Providers.Entities.ModelHelper.CreateMembershipEntities(ConnectionStringSettings setting)
       at System.Web.Providers.DefaultMembershipProvider.Membership_CreateUser(String applicationName, String userName, String password, String salt, String email, String passwordQuestion, String passwordAnswer, Boolean isApproved, DateTime& createDate, Boolean uniqueEmail, Int32 passwordFormat, Object& providerUserKey)
       at System.Web.Providers.DefaultMembershipProvider.CreateUser(String username, String password, String email, String passwordQuestion, String passwordAnswer, Boolean isApproved, Object providerUserKey, MembershipCreateStatus& status)
       at System.Web.Security.Membership.CreateUser(String username, String password, String email, String passwordQuestion, String passwordAnswer, Boolean isApproved, Object providerUserKey, MembershipCreateStatus& status)
       at WcfLoginRegister.RegistrationService.RegisterUser(RegisterUserRequest request) in C:\Users\rmacgrogan\dev\pallas\parthenon\sandbox\FbEntityTypeTester\WcfLoginRegister\RegistrationService.svc.cs:line 43
       at SyncInvokeRegisterUser(Object , Object[] , Object[] )
       at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)
       at     System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)
  InnerException: System.Transactions.TransactionException
       Message=The operation is not valid for the state of the transaction.
       Source=System.Transactions
       StackTrace:
            at     System.Transactions.TransactionState.EnlistPromotableSinglePhase(InternalTransaction tx, IPromotableSinglePhaseNotification promotableSinglePhaseNotification, Transaction atomicTransaction)
            at System.Transactions.Transaction.EnlistPromotableSinglePhase(IPromotableSinglePhaseNotification promotableSinglePhaseNotification)
            at System.Data.SqlClient.SqlInternalConnection.EnlistNonNull(Transaction tx)
            at System.Data.SqlClient.SqlInternalConnection.Enlist(Transaction tx)
            at System.Data.SqlClient.SqlInternalConnectionTds.Activate(Transaction transaction)
            at System.Data.ProviderBase.DbConnectionInternal.ActivateConnection(Transaction transaction)
            at System.Data.ProviderBase.DbConnectionPool.GetConnection(DbConnection owningObject)
            at System.Data.ProviderBase.DbConnectionFactory.GetConnection(DbConnection owningConnection)
            at System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory)
            at System.Data.SqlClient.SqlConnection.Open()
            at System.Data.SqlClient.SqlProviderServices.UsingConnection(SqlConnection sqlConnection, Action`1 act)
            at System.Data.SqlClient.SqlProviderServices.UsingMasterConnection(SqlConnection sqlConnection, Action`1 act)
            at System.Data.SqlClient.SqlProviderServices.GetDbProviderManifestToken(DbConnection connection)
            at System.Data.Common.DbProviderServices.GetProviderManifestToken(DbConnection connection)
   InnerException: 

更新

我做了一个简化的测试以更好地访问真正的底层错误,而Bahri Gungor是正确的,因为潜在的问题是MSDTC没有启用。

但是,由于我尝试在Azure项目中运行此代码,并且由于Azure不支持分布式事务,因此我使用了一种丑陋的解决方法。所有成员资格写入必须在单独的交易中进行,这非常不幸。

感谢大家的帮助。

2 个答案:

答案 0 :(得分:4)

我没有尝试将TransactionScope与ASPNet Membership Services一起使用,但是,任何打开另一个事务(甚至是数据库的第二个连接)的东西都会自动初始化MSDTC事务。如果未在计算机上配置MSDTC(我假设您的Web服务器),则无法成功创建事务。

在“管理工具”下,有一个名为“组件服务”的管理工具(“控制面板” - >“系统和安全性” - >“管理工具”)。工具打开后,您将在左侧看到组件服务。开放组件服务 - >计算机 - >我的电脑 - >分布式事务协调器 - >本地DTC(右键单击并选择“属性”)。选择“安全”选项卡。

确保事务管理器通信同时选中允许入站和允许出站。还应检查网络DTC访问。我不能对其他设置有任何具体的说明,因为您的特定环境可能需要对其他变量进行不同的设置。

我相信正在发生的事情是您对ASPNet成员资格服务(具有自己的SQL Server配置)的访问正在将事务提升为MSDTC事务,并且某些设置(MSDTC的安全性或配置)阻止其成功。您可以通过简单的Google搜索找到各种MSDTC故障排除文献(其中许多都是在Stack Overflow上解决的)。但是,我会首先检查您的组件服务配置,并确保您可以执行分布式事务。

答案 1 :(得分:2)

当您嵌套了事务范围时,可能会导致这种情况:

        using (var ts = new TransactionScope())
        {
            using(var tsInner1 = new TransactionScope())
            {
                //OOPS, I forgot to call Complete() or Rollback()
            }
            using (var tsInner2 = new TransactionScope())
            {
                //Any db action followed by a "Complete" will cause this error
                tsInner2.Complete();
            }
        }

但是如果没有看到产生错误的代码,我无法确定。