[英]DDD Architecture for ASP.NET MVC2 Project
我正在嘗試使用域驅動開發(DDD)來實現我的新ASP.NET MVC2項目和實體框架4.在做了一些研究之后,我在自己的類項目中為每個層提出了以下層約定:
MyCompany.Domain
public class User
{
//Contains all the properties for the user entity
}
public interface IRepository<T> where T : class
{
IQueryable<T> GetQuery();
IQueryable<T> GetAll();
IQueryable<T> Find(Func<T, bool> condition);
T Single(Func<T, bool> condition);
T First(Func<T, bool> condition);
T GetByID(int id);
void Delete(T entity);
void Add(T entity);
void Attach(T entity);
void SaveChanges();
}
public interface IUserRepository: IRepository<User> {}
public class UserService
{
private IUserRepository _userRepository;
public UserService(IUserRepository userRepository)
{
_userRepository = userRepository;
}
// This class will hold all the methods related to the User entity
}
MyCompany.Repositories
public class UserRepository : IRepository<User>
{
// Repository interface implementations
}
MyCompany.Web - >這是MVC2項目
目前,我的Repositories層包含對Domain層的引用。 根據我的理解,將UserRepository注入UserService類可以很好地進行單元測試,因為我們可以傳入虛假的用戶存儲庫。 因此,使用此體系結構,我的Web項目看起來需要引用我的域和存儲庫層。 但這是有效的嗎? 因為歷史上表示層只有對業務邏輯層的引用。
關於@ RPM1984的一些注釋答案......
但是在你的問題中,你在域項目中有了IRepository,我會把它放在你的Repositories程序集中。
雖然在物理上放置物品並不重要,但重要的是要記住存儲庫的抽象是域的一部分。
我們還有一個在UI(控制器)和存儲庫之間進行調解的服務層。 這允許中央位置放置不屬於存儲庫的邏輯 - 諸如分頁和驗證之類的東西。
我認為,僅為分頁和驗證創建服務並不是一個好主意。 更糟糕的是,如果它是人工創建的 - 只是因為'一切都通過服務'和'那樣你不需要從UI引用存儲庫'。 應盡可能避免應用程序服務。
對於輸入驗證 - 開箱即用已經很好了。 如果您使用asp.net mvc,請考慮以下MVVM模式和框架將提供足夠好的方法來驗證您的輸入視圖模型。
如果您需要跨多個聚合根進行交互(這表明您可能缺少新的聚合根) - 編寫域服務。
您似乎走在正確的軌道上,但由於它似乎想要“DDD-All-The-Way”,您是否考慮過實施工作單元模式來管理共享相同上下文的多個存儲庫?
我認為應該避免工作單位。 原因如下:
另一個例子,UoW實際上是一個基礎設施問題,為什么你會把它帶到域? 如果您的聚合邊界正確,則不需要工作單元。
存儲庫不屬於域。 存儲庫是關於持久性(即基礎架構),域是關於業務的。
存儲庫負有混合責任。 從一方面來看 - 企業並不關心數據的持久性和方式。 來自其他人 - 通過購物車內容可以找到客戶的知識(簡化示例)。 因此 - 我認為只有抽象應該是域的一部分。 另外 - 我反對從域模型直接使用存儲庫,因為它應該是持久性無知的。
服務層允許“業務驗證”的中心點。
應用服務基本上只是外觀 。 如果復雜性增加了它所解決的超重問題,那么每個外觀都是糟糕的。
這是一個糟糕的外觀:
public int incrementInteger(int val){
return val++;
}
應用程序服務不得包含業務規則。 這就是域驅動設計的重點 - 無處不在的語言和孤立的代碼,它們盡可能清晰,簡單地反映業務。
MVC適用於簡單驗證,但不適用於復雜的業務規則(思考規范模式)。
這就是它應該用於的東西。 例如 - 檢查發布的值是否可以解析為日期時間,該日期時間應該作為參數傳遞給域。 我稱之為UI驗證。 他們中有很多人 。
RE UoW - 我被這句話打擾了,但你能詳細說明嗎? UoW確實是一個基礎設施問題,但這又是我的存儲庫/數據層,而不是我的域。 我的所有域名都是業務對象/規范。
工作單元模式鼓勵我們放松聚合根邊界。 基本上 - 它允許我們在多個根目錄上運行事務。 盡管它位於域之外,但它仍然會對我們制定的域和建模決策產生隱含影響。 通常它會導致所謂的貧血領域模型。
還有一件事: 圖層!=層 。
我要做的另一點是DDD是一個指導方針,而不是一個全能的方法。
是的,但這不應該被用作借口。 :)
我們服務層的另一個原因是我們有一個Web API。 我們不希望我們的Web API調用我們的存儲庫,我們需要一個很好的流暢的界面,Web App和API都可以調用它。
如果沒有什么比檢索root並調用它的方法 - 只是為了包裝而沒有必要。 因此 - 我懷疑你真正的問題是缺乏這種孤立,因此 - 需要協調根之間的互動。
在這里您可以看到我當前方法的一些細節。
我們的服務層的另一個重要原因是我們的存儲庫返回IQueryable,因此它們沒有任何邏輯。 我們的服務層將linq表達式投射到混凝土中
這聽起來不對。 同樣的問題 - 缺乏隔離。
在這種情況下 - 存儲庫不足以抽象持久性。 他們應該有邏輯 - 一個與持久性相關的邏輯。 了解如何存儲和檢索數據。 委托“外面某處”會破壞存儲庫的整個點以及剩下的所有內容 - 一個模擬數據訪問以進行測試的擴展點(這不是壞事)。
另一件事 - 如果存儲庫返回原始IQueryable
,它會自動將服務層與未知(!)LINQ提供程序聯系起來。
並且不那么糟糕(你甚至可能不需要) - 由於高耦合 ,將持久性轉換為另一種技術可能非常困難。
不要忘記我們正在談論技術問題。 這些東西與設計本身無關,它們只是讓它成為可能。
如果您不使用服務層,您將如何(例如)檢索產品的訂單列表? 您需要一個名為“GetOrdersForProduct”的存儲庫中的方法 - 我認為這不是一個好的設計。 您的存儲庫界面變得龐大,無法維護。 我們使用非常通用的存儲庫(查找,添加,刪除等)。 這些方法可以解決模型中設置的對象。 多功能/查詢功率被提供給服務層
這個很棘手。 我只想留下好的參考 。
對於未知的提供者,我的意思是 - 你現在不能真正從服務層下面得到什么。 它可能是Linq to objects,它可能是Linq to xml,Linq to sql,NHIbernate.Linq以及其他一些提供程序實現。 不好的是 - 你不知道支持什么。
如果它是對象的Linq,這將運行正常,如果需要轉換為sql將失敗:
customers.Where(c=>{var pickItUp=c.IsWhatever; return pickItUp;});
這非常有效,實際上與我們的設置非常相似。
但是在你的問題中,你在域項目中有了IRepository
,我會把它放在你的Repositories程序集中。
您的域層應具有您的域實體和業務邏輯。 您的存儲庫層應該具有通用存儲庫接口,以及每個聚合根的一個具體實現。
我們還有一個在UI(控制器)和存儲庫之間進行調解的服務層。 這允許中央位置放置不屬於存儲庫的邏輯 - 諸如分頁和驗證之類的東西。
這樣,UI不引用存儲庫,僅引用服務層。
我們還使用DI將EntityFrameworkRepository注入我們的服務層,並將MockRepository注入我們的測試項目。
您似乎走在正確的軌道上,但由於它似乎想要“DDD-All-The-Way”,您是否考慮過實施工作單元模式來管理共享相同上下文的多個存儲庫?
您可能想要探索Sharp Architecture框架解決此問題的方式,因為看起來您基本上是在重新實現相同的想法。 Northwind應用程序教程對這些概念進行了一些很好的討論。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.