TransactionScope 内的 Membership.GetUser() 抛出 TransactionPromotionException

2023-12-02

下面的代码抛出一个TransactionAbortedException带有消息“交易已中止”和内部TransactionPromotionException消息“尝试促进交易失败”:

    using ( TransactionScope transactionScope = new TransactionScope() )
    {
        try
        {
            using ( MyDataContext context = new MyDataContext() )
            {
                Guid accountID = new Guid( Request.QueryString[ "aid" ] );
                Account account = ( from a in context.Accounts where a.UniqueID.Equals( accountID ) select a ).SingleOrDefault();
                IQueryable < My_Data_Access_Layer.Login > loginList = from l in context.Logins where l.AccountID == account.AccountID select l;

                foreach ( My_Data_Access_Layer.Login login in loginList )
                {
                    MembershipUser membershipUser = Membership.GetUser( login.UniqueID );
                }

                [... lots of DeleteAllOnSubmit() calls]

                context.SubmitChanges();
                transactionScope.Complete();
            }   
        }

        catch ( Exception E )
        {
        [... reports the exception ...]
        }
    }

错误发生在调用Membership.GetUser().

我的连接字符串是:

      <add name="MyConnectionString" connectionString="Data Source=localhost\SQLEXPRESS;Initial Catalog=MyDatabase;Integrated Security=True"
   providerName="System.Data.SqlClient" />

我拥有的一切read告诉我TransactionScope应该会神奇地应用于会员调用。用户存在(否则我希望返回 null。)


The TransactionScope类屏蔽异常。最有可能发生的情况是该范围内的某些内容失败(引发异常),并且TransactionAbortedException只是控制退出时发生的副作用using block.

尝试将所有东西都包裹在里面TransactionScope in a try-catch块,并在块内重新抛出catch,并在那里设置断点;你应该能够看到真正的错误是什么。

另一件事,TransactionScope.Complete应该是结束之前执行的最后一条语句using块包含TransactionScope。在这种情况下,您可能应该没问题,因为您之后实际上并没有做任何工作,而是调用Complete在内部作用域内往往会产生更容易出现错误的代码。


Update:

现在我们知道了内部异常是什么(促进交易失败),就更清楚发生了什么。

问题是在里面TransactionScope,您实际上是在打开另一个数据库连接GetUser。会员提供商不知道如何重新使用DataContext你已经打开了;它必须打开自己的连接,并且当TransactionScope看到这一点,它尝试升级为分布式事务。

它失败是因为您可能在 Web 服务器、数据库服务器或两者上禁用了 MSDTC。

如果您要打开两个单独的连接,则无法避免分布式事务,因此实际上有几种方法可以解决此问题:

  1. 移动GetUser calls outside the TransactionScope。也就是说,首先从成员资格提供程序将用户“读取”到列表中,然后在实际需要开始进行修改时启动事务。

  2. 去除GetUser一起调用并直接从数据库读取用户信息,在同一DataContext或者至少是相同的连接。

  3. 在参与事务的所有服务器上启用 DTC(事务升级时性能将受到影响)。

我认为选项#1 在这种情况下是最好的;您需要从会员提供商处读取的数据在您读取数据的时间和开始交易的时间之间不太可能发生更改。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

TransactionScope 内的 Membership.GetUser() 抛出 TransactionPromotionException 的相关文章

随机推荐