当前位置 : 主页 > 编程语言 > c语言 >

c# – TransactionScope中的Membership.GetUser()抛出TransactionPromotionException

来源:互联网 收集:自由互联 发布时间:2021-06-25
以下代码抛出TransactionAbortedException,消息“事务已中止”,内部TransactionPromotionException,消息“尝试提升事务时失败”: using ( TransactionScope transactionScope = new TransactionScope() ) { try { using ( My
以下代码抛出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.)

TransactionScope类掩盖了异常.很可能发生的事情是该范围内的某些内容失败(抛出异常),而TransactionAbortedException只是当控件退出using块时发生的副作用.

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

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

更新:

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

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

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

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

>在TransactionScope外部移动GetUser调用.也就是说,首先从会员提供者“读取”用户到列表中,然后在实际需要开始修改时启动事务.
>完全删除GetUser调用并直接从数据库,同一DataContext或至少相同的连接读取用户信息.
>在参与交易的所有服务器上启用DTC(当事务提升时,性能将受到影响).

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

网友评论