2012-02-28 38 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