TransactionScope中的Membership.GetUser()抛出TransactionPromotionException

Bob*_*man 3 c# linq asp.net-membership transactions

以下代码抛出一条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 ...]
        }
    }
Run Code Online (Sandbox Code Playgroud)

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

我的连接字符串是:

      <add name="MyConnectionString" connectionString="Data Source=localhost\SQLEXPRESS;Initial Catalog=MyDatabase;Integrated Security=True"
   providerName="System.Data.SqlClient" />
Run Code Online (Sandbox Code Playgroud)

读过的所有内容都告诉我,TransactionScope应该只是神奇地应用于会员电话.用户存在(否则我希望返回null.)

Aar*_*ght 6

TransactionScope类口罩例外.最有可能发生的事情是该范围内的某些内容失败(抛出异常),而这TransactionAbortedException只是控件退出using块时发生的副作用.

尝试将所有内容包装TransactionScope在一个try-catch块中,并在其中进行重新抛出catch,并在那里设置断点; 你应该能够看到真正的错误是什么.

另一件事,TransactionScope.Complete应该是在using包含的块结束之前执行的最后一个语句TransactionScope.在这种情况下,你可能应该没问题,因为之后你实际上并没有做任何工作,但是将调用Complete放在内部范围内往往会导致更容易出错的代码.


更新:

既然我们知道内部异常是什么(失败促进交易),那么更清楚的是发生了什么.

问题是,在内部TransactionScope,你实际上正在打开另一个数据库连接GetUser.会员提供者不知道如何重新使用DataContext您已经开放的; 它必须打开自己的连接,当TransactionScope看到它时,它会尝试升级到分布式事务.

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

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

  1. 移动GetUser电话以外TransactionScope.也就是说,首先从会员提供者"读取"用户到列表中,然后在实际需要开始修改时启动事务.

  2. GetUser完全删除调用并直​​接从数据库中,在相同DataContext或至少相同的连接上读取用户信息.

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

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