0

我正在将 asp.net 成员资格升级到 MVC4 中新的 simplemembership 提供程序。这是一个 Azure/Sql Azure 应用程序,它在 localhost 上运行良好,但在部署时失败。我在事务中有如下代码:

            TransactionOptions toptions = new TransactionOptions();
            toptions.IsolationLevel = System.Transactions.IsolationLevel.Serializable;
            using (TransactionScope trans = new TransactionScope(TransactionScopeOption.Required, toptions))
            {
                try
                {
                   ... do a bunch of database stuff in a single dbContext ...

                   var roleprov = (SimpleRoleProvider)Roles.Provider;
                   string[] roles = roleprov.GetRolesForUser(Username);
                   // above line fails with The transaction manager has disabled its support for remote/network transactions. (Exception from HRESULT: 0x8004D024)
                 }
             }

我正在使用这种技术来填充角色类。堆栈跟踪似乎表明它确实在尝试触发子事务以完成该调用。simplemembership 表位于不同的数据库中。如何在单独事务的上下文中从角色提供者检索角色信息?

4

1 回答 1

0

问题是这GetRolesForUser会导致新连接打开到第二个数据库,然后又会发现它位于TransactionScope. 反过来,这(MSDN - System.Transactions 与 SQL Server 集成)然后提升到 DTC。你可以尝试几个选项:

在事务开始之前获取角色

您可以string[] roles TransactionScope. 您是否有理由需要将它们纳入范围?鉴于你说:

如何在单独事务的上下文中从角色提供者检索角色信息

听起来您可以在之前获得角色信息TransactionScope并且没有问题。

关闭简单成员连接字符串上的事务

您可以通过将“enlist=false”(参见 参考资料)放在连接字符串中来告诉连接字符串不参与事务SqlConnection.ConnectionString,因此如果您从不需要用于简单成员资格的数据库上的事务,这可能是您的一种选择。

尝试在交易前打开 Simple Membership 连接

因为SimpleRoleProvider它创建了它的数据库对象,然后在第一次使用它时打开它。但是,它直到...才关闭它从头开始,每次调用都会打开连接,GetRolesForUser所以你不走运。我在想你可以在打开GetRolesForUser之前调用一次TransactionScope,然后在范围内使用已经打开的连接再次调用 - 你不能。

IObjectContextAdapter

免责声明:我不能保证这会起作用,因为我无法使用您的设置进行测试。

您可以通过首先打开事务范围之外的非事务连接字符串来防止使用两个连接字符串进行提升,然后不应该提升事务。如果您在相同的事务范围内产生相同的连接(否则会导致提升),Close也可以使用此方法。Open

您可以在您的上下文中尝试此操作,并查看是否停止了 GetRolesForUser 促进事务,但我怀疑这是否会GetRolesForUser导致连接打开(如果尚未打开)。由于我无法在您的场景中进行测试,因此我将包括它以防万一。

using (var db = new ExampleContext())
{
    var adapter = db as System.Data.Entity.Infrastructure.IObjectContextAdapter;
    using (var conn = adapter.ObjectContext.Connection)
    {
        conn.Open();
        using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required))
        {
            // perform operations
            db.SaveChanges();
            // perform more operations
            db.SaveChanges();
            // perform even more operations
            db.SaveChanges();

            //  If you don't complete, the transaction won't commit and you will lose the changes
            scope.Complete();
        }
    }
}
于 2013-05-22T18:46:50.240 回答