在单个事务上包装成员资格提供程序和dbcontext

时间:2012-09-07 16:02:42

标签: asp.net-mvc entity-framework asp.net-membership

首先使用EF 5代码和.NET 4.5的MVC项目。

我一直在寻找一种在单个事务上包装dbContext和SimpleMembershipProvider的方法。我尝试使用TransactionScope,但由于成员资格提供者将打开另一个连接,我得到一个例外(服务器'servername'上的MSDTC不可用)。

所以我虽然可以使用ObjectContext.Connection.BeginTransaction代替。 成员资格提供者不会成为交易的一部分,但想法是将其置于某个地方,如果失败,交易将不会被提交。

Book bk1 = default(Book);
Book bk2 = default(Book);

object obc = (IObjectContextAdapter)dbContext;

obc.ObjectContext.Connection.Open();
using (tx == obc.ObjectContext.Connection.BeginTransaction) {

    bk1 = new Book {
        Name = "Book 1 Name",
        Location = "USA"
    };
    dbContext.Books.Add(bk1);
    dbContext.SaveChanges();
    bk2 = new Book {
        Name = "Book 2 Name. Book one Id is: " + bk1.Id,
        Location = "USA"
    };
    dbContext.Books.Add(bk2);
    dbContext.SaveChanges();

    // this is not part of the transaction, 
    // however if it trhows an exception the transaction is aborted.
    // I'm assuming that if we got here, the commit won't fail...    
    // But is it really true?
    WebSecurity.CreateUserAndAccount("username", "123456");

    tx.Commit();
}

无论如何,基于上面的代码:

  • 如果WebSecurity.CreateUserAndAccount失败,整个过程就会失败,这是预期的。
  • 如果任何SaveChanges方法失败,那么整个事情都会失败,因为我们没有达到执行CreateUserAndAccount的程度。

这件事给我带来了一个问题: 安全吗?我的意思是:

在我们成功执行DbContext.SaveChanges之后,“Commit”方法是否有可能抛出异常(以某种方式失败)?如果它发生,我们将与孤儿用户结束,因为提供者不是交易的一部分。

我对此有任何意见或建议表示感谢。

快速说明: 有一篇很好的文章解释了为什么我必须将dbContext转换为IObjectContextadapter而不是使用自己的连接属性,但我再也找不到它了。

1 个答案:

答案 0 :(得分:2)

是的,Commit当然可以扔掉。一个简单的例子是连接是否下降。当然还有其他情况。

您有几个选择:

  • 如果共享连接,则同一数据库上的事务不会升级为分布式。因此,您可以为EF和WebSecurity连接使用一个连接。
  • 在服务器上启动分布式事务控制器并使用升级。这不是世界上最糟糕的事情。
  • 不使用事务,而是更改操作的顺序,以便可以在以后完成或撤消部分成功的操作。例如,检测并清理“孤儿”用户。