在TransactionScope中注册System.Web.Providers

13
我们正在尝试将System.Web.Providers成员管理集成到使用System.Transactions.TransactionScope的事务中,但不断收到以下错误消息:
The operation is not valid for the state of the transaction.

包装在一个异常中,带有以下更令人困惑的消息:

The provider did not return a ProviderManifestToken string.

在有人问之前,是的我们已经验证了连接字符串的正确性,并且我们用于连接数据库的用户具有适当的权限。如果我们把尝试调用Membership.CreateUser()方法的代码从TransactionScope块中拿出来,则它可以正常工作。将其放入TransactionScope中会导致失败。

似乎关于Universal Provider的信息非常少。几乎所有你看到的都是指向NuGet页面和Scott Hanselman在6月份发布的博客文章。

有人知道如何使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不支持分布式事务,因此我被迫使用一个丑陋的解决方法。所有成员资格编写必须出现在单独的事务中,这非常不幸。

感谢大家的帮助。


我想知道你是否能够发布你所尝试做的代码? - Mark Gibbons
看看这个网址http://progtutorials.tripod.com/DotNetTransaction.htm,可能会有所帮助。 - Jahan Zinedine
你能否发布一下你正在使用的调用 Membership.CreateUser() 的代码? - Strillo
问题的根源在于内部异常。这是一个相当通用的异常,意味着底层事务存在一些问题... 这可能意味着 MSDTC 没有运行或无法访问(防火墙等)。您可以尝试使用事务范围执行简单的“纯” SQL 操作,看看是否有效?这也可能是由于超时引起的。请参见 http://msdn.microsoft.com/en-us/library/system.transactions.configuration(v=VS.100).aspx 以更改默认的 tx 超时时间。 - Simon Mourier
谢谢大家的反馈,对于我回复迟迟未能及时作出道歉。 - Robert MacGrogan
显示剩余2条评论
2个回答

4
我没有尝试过在ASPNet会员服务中使用TransactionScope,但是任何打开另一个事务的操作(即使是连接到数据库的第二个连接)都将自动初始化MSDTC事务。如果机器上未配置MSDTC(我假设您的Web服务器),则无法成功创建事务。
在“管理工具”下,有一个名为“组件服务”的管理工具(控制面板->系统和安全->管理工具)。一旦打开该工具,您将在左侧看到组件服务。打开组件服务->计算机->我的计算机->分布式事务协调器->本地DTC(右键单击并选择属性)。 选择“安全”选项卡。
确保“事务管理器通信”中同时选中了“允许入站”和“允许出站”。网络DTC访问也应该被选中。对于其他设置,我无法更加具体,因为您的特定环境可能需要不同的变量设置。
我认为发生的情况是您访问ASPNet会员服务(其具有自己的SQL Server配置)正在将事务提升为MSDTC事务,而某些设置(MSDTC的安全或配置)正在阻止它成功执行。您可以通过简单的谷歌搜索找到所有类型的MSDTC故障排除文献(其中许多问题已在Stack Overflow上得到解决)。然而,我建议您首先检查组件服务配置,并确保您能够执行分布式事务。

请确保在管理工具/服务下启动了“分布式事务协调器”服务。 - Frank.Germain

2
这可能是由于嵌套的TransactionScopes造成的:
        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();
            }
        }

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


要创建错误,请在事务范围内调用 ASP.NET 成员资格提供程序(使用 SQL Server 的那个)的 create user 方法。 - Peter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接