C# TransactionScope中的Membership.GetUser()引发TransactionPromotionException
下面的代码抛出带有消息“事务已中止”的C# TransactionScope中的Membership.GetUser()引发TransactionPromotionException,c#,linq,transactions,asp.net-membership,C#,Linq,Transactions,Asp.net Membership,下面的代码抛出带有消息“事务已中止”的TransactionBortedException,以及带有消息“尝试升级事务时失败”的内部TransactionPromotionException: 我所告诉我的一切,TransactionScope应该神奇地应用于会员资格调用。用户存在(否则我希望返回空值)。在一个级别上,它是正确的;事务始终被中止(您没有调用Complete()。那是准确的密码吗 此外,将DataContext放在TransactionScope之外会让我怀疑它可能在做一些奇怪的事
TransactionBortedException
,以及带有消息“尝试升级事务时失败”的内部TransactionPromotionException
:
我所告诉我的一切,
TransactionScope
应该神奇地应用于会员资格调用。用户存在(否则我希望返回空值)。在一个级别上,它是正确的;事务始终被中止(您没有调用Complete()。那是准确的密码吗
此外,将DataContext
放在TransactionScope
之外会让我怀疑它可能在做一些奇怪的事情,因为在创建数据上下文时,事务并不在那里。您是否尝试过(两种):
- 颠倒创建顺序,使
跨越TransactionScope
DataContext
- 呼叫
Complete
TransactionScope
类屏蔽异常。最有可能发生的情况是,该范围内的某些内容失败(引发异常),而TransactionAbortedException
只是控件使用块退出时发生的副作用
尝试将TransactionScope
中的所有内容包装到Try catch
块中,并在catch
中重新执行,然后在那里设置断点;您应该能够看到真正的错误是什么
还有一件事,TransactionScope.Complete
应该是使用包含TransactionScope
的块在结束之前执行的最后一条语句。在这种情况下,您可能会没事,因为您之后实际上没有做任何工作,但是将对Complete
的调用放在一个内部作用域中往往会产生更容易出现错误的代码
更新:
现在我们知道了内部异常是什么(失败促进事务),接下来就更清楚了
问题在于,在事务范围内
,您实际上正在使用GetUser
打开另一个数据库连接。会员资格提供商不知道如何重新使用您已经打开的DataContext
;它必须打开自己的连接,当TransactionScope
看到这一点时,它会尝试升级到分布式事务
它失败是因为您可能在web服务器、数据库服务器或两者上禁用了MSDTC
如果要打开两个单独的连接,则无法避免分布式事务,因此有几种方法可以解决此问题:
将GetUser
调用移到TransactionScope
之外。也就是说,首先将用户从成员资格提供程序“读取”到列表中,然后在实际需要开始进行修改时启动事务
完全删除GetUser
调用,并在相同的DataContext
或至少相同的连接上直接从数据库读取用户信息
在参与事务的所有服务器上启用DTC(事务升级时性能将受到影响)
我认为,在这种情况下,选项1将是最好的;您需要从会员资格提供商处读取的数据在您读取数据和开始交易之间不太可能发生更改。GetUser
做什么?如果您只是在查询东西,那么TransactionScope
需要什么?GetUser()是Microsoft成员资格API的一部分。为了可读性,我删除了很多代码,这些代码删除了一个帐户的所有登录名,然后删除了该帐户本身。我根据您的建议,在这里和代码中转置了TransactionScope和DataContext控件,但都没有用。我还在代码中添加了对Complete()的调用,以更好地反映我的代码,而不会引入来自原始源代码的大量噪音。另一个有价值的见解!我已经在使用块外设置了一个try-catch块。我会把它移到里面,相应地编辑上面的代码,然后很快回来报告。。。。不。还是同一个例外,同一行。值得注意的是——注释掉TransactionScope,它就可以正常工作了。同样值得注意的是——内部异常消息“尝试升级事务时失败”@Bob Kaufman:实际上,该内部异常是最重要的异常。稍后将解释为什么……我成功地选择了选项2。谢谢大家!#1不实用;我正在选择一个“帐户”,然后枚举并删除该帐户下的所有登录名#3-我们都同意这在很多层面上都是坏消息。我在服务器上启用了DTC,但在调用web方法时仍会出现此错误。有人知道为什么吗?基本上我在列表上做了3个,1或2个不适用于我,它仍然不起作用。
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 ...]
}
}
<add name="MyConnectionString" connectionString="Data Source=localhost\SQLEXPRESS;Initial Catalog=MyDatabase;Integrated Security=True"
providerName="System.Data.SqlClient" />
using ( TransactionScope transactionScope = new TransactionScope() )
using ( MyDataContext context = new MyDataContext() )
{
/* ... */
transactionScope.Complete();
}