2012-02-28 35 views
3

我在将单体ASP.NET MVC应用程序拆分为N层应用程序时遇到了很多困难。在下面的示例中,在第一次调用_messageRepo.Create()期间抛出异常,指出DbContext由于已被丢弃而无法使用。我的DbContext被如何处理?

我看不到如何发生这种情况,并试图在上中止Dispose()方法实际上并不会导致应用程序在调试过程中中断。

的基本结构如下:

  • 控制器与每个服务的实例注入他们使用//即:公共myController的(IMessageService messageService)
  • 服务包含库的任何需要的情况下(即: _messageRepository
  • 库利用MyContext的一个实例,一个子类的的DbContext
  • 每当需要作为在下面的示例中个
  • 这些实例被重建

    using(var context = new MyContext()) 
    { 
        _messageRepo = new MessageRepository(context); 
        _idRepo = new IdentityRepository(context); 
    
        var status = _messageRepo.GetStatus(Int32.Parse(message.To)); 
        message.To = status.Header.From.Name; 
        message.ToHash = Obfuscate.SaltAndHash(message.To); 
        message.Subject = "RE:" + status.Header.Subject; 
    
        var toUser = _idRepo.Get(message.To); 
        var fromUser = _idRepo.Get(_userName); 
        var rawMessage = new Message() 
        { 
         Content = message.Content, 
         Attachments = GetAttachments(message.AttachmentIds) 
        }; 
        var header = new MessageHeader() 
        { 
         To = toUser, 
         From = fromUser, 
         Subject = message.Subject 
        }; 
        _messageRepo.Create(new MessageStatus() 
        { 
         CreatedAt = DateTime.Now, 
         IsRead = false, 
         IsSpam = false, 
         IsTrash = false, 
         Message = rawMessage, 
         Header = header, 
         Owner = header.To 
        }); 
        _messageRepo.Create(new MessageStatus() 
        { 
         CreatedAt = DateTime.Now, 
         IsRead = false, 
         IsSpam = false, 
         IsTrash = false, 
         Message = rawMessage, 
         Header = header, 
         Owner = header.From 
        }); 
        context.Commit(); 
        Email.SendNewMessageNotification(fromUser.Email, toUser.Email); 
    } 
    

存储库的方法是检索使用代码优先的方法从通过实体框架一个数据库模型LINQ单行。

这种方法有什么问题吗?我确实有MyContext首先实现IUnitOfWork,但我删除了,直到我得到这个不太复杂的方法功能。

此外,我正在使用IoC framwork(AutoFac)来加载这些接口实现的实例。如果这是问题,那么我需要改变我的逻辑以适应AutoFac?

//in Global.asax.cs 
builder.RegisterType<PonosContext>().As<PonosContext>().InstancePerHttpRequest(); 

//Example repo constructor 
public MessageRepository(PonosContext context) 
{ 
    _db = context; 
} 

回答

2

当您使用IoC容器时,不应该调用容器管理的服务的新增内容。在这个例子中你不应该使用:

using(var context = new MyContext()) 
_messageRepo = new MessageRepository(context); 
_idRepo = new IdentityRepository(context); 

你的依赖关系应该被注入(例如通过构造函数)。

如何使用AutoFac注册存储库?也许你有你的仓库configurard单身?当存储库重用于第二个http请求时,这可能导致处理异常。

+0

最初,我将每个HTTP请求的上下文连接为一个实例。这是抛出其他EF例外,这导致我采取这种做法。我可以通过将MyContext重新实现为IUnitOfWork并使用不同的注册方法再次将它连接到AutoFac中,从而使用块来摆脱所有这些问题? – XBigTK13X 2012-02-28 16:20:11

+0

另外,我只能通过(_unitOfWork as MyContext)访问MyContext中的DbSets。我认为这导致了一些不同的EF异常,是否有更好的方法在构造函数中拥有一个接口,但根据需要访问上下文的基础属性? – XBigTK13X 2012-02-28 16:22:10

0

DataContexts不应该活太长:)他们应该被创建和处置接近他们的使用。

请考虑不要在不同的存储库之间传递相同的实例。如果要在单个事务中包装多个操作,请参阅TransactionScope

+0

尽管我同意这种观点,但我需要能够使用一个repo调用(GetStatus())的结果作为传入其他repo调用的模型的输入。如果我在这些步骤之间放置上下文,那么访问MessageStatus的延迟加载成员将抛出关于正在处理的上下文的异常。 – XBigTK13X 2012-02-28 15:54:28

+0

在看到有关TransactionScope的注释之后,我尝试在另一个使用块中包装上述示例,但使用上下文后的scope.Complete不能解决问题。 – XBigTK13X 2012-02-28 16:05:32

+1

恕我直言,应该在单个服务/ http调用期间使用相同的上下文。 DbContext表示一个UnitOfWork,它是一个业务事务,所以对于单个操作(service/http调用)的所有修改都是通过相同的DbContext进行的。你的DbContext应该永远不会长时间作为一个Http调用。但是在同一个操作中你使用了不同的DbContext,你放弃了ORM的很多好处。 – 2012-02-28 16:15:11