2011-04-02 142 views
6

我想學習ASP.Net的MVC和我正在讀史蒂夫桑德森的書。我困惑的一件事是放置業務邏輯的地方在哪裏?MVC商業邏輯組織

例如,刪除產品時,Sanderson擁有的是CartController中的一個方法,該方法調用productsRepository上的Delete方法。這對我來說很奇怪,因爲如果有任何業務邏輯,例如確保產品不在任何人的購物車中,那麼它必須位於產品存儲庫或CartController中。

這兩者似乎都是不好的放置商業邏輯的地方;產品庫意味着可以很容易地用另一個替換(從使用數據庫切換到使用會話),使用Controller意味着您將業務邏輯放入UI層。

他不應該使用包含業務邏輯的類並調用存儲庫的刪除方法嗎?該存儲庫是業務邏輯類的成員變量'?

回答

3

我還閱讀了Sanderson的第一版他的書,它非常棒 - 這是一種非常簡單的方法來獲取並開始使用ASP.NET MVC。不幸的是,你不能直接從他書中的概念跳到編寫大型可維護應用程序。最大的障礙之一是找出將業務邏輯和其他問題放在UI和持久存儲之間的位置(稱爲分離問題或SOC)。

如果您有興趣,請考慮閱讀Domain Driven Design。我不會建議我完全瞭解它,但是可以從Sanderson的示例應用程序轉換爲成功分離UI關注點,業務邏輯和存儲問題的良好過渡。

我的解決方案有一個單獨的服務層。控制器與服務層進行通信(使用依賴注入 - Ninject)。服務層可以訪問我的域對象/業務邏輯和我的存儲庫(NHibernate - 也與Ninject合作)。我的觀點或控制器中的邏輯很少 - 控制器用於協調員的目的,我努力保持控制器的操作儘可能的簡單。

我的域層(實體,業務邏輯等)沒有依賴關係。它沒有對我的Web項目或我的Repository項目的引用。它通常被稱爲POCO或Plain Old C#/ CLR對象。

編輯:我注意到您使用EF的評論之一。 EF不支持POCO而不使用Code First(當我在去年8月檢查時處於社區技術預覽狀態)。只是FYI。

+0

一個很好的答案 - 你可能會添加一個你的項目結構的插圖嗎? – flesh 2011-04-02 20:48:03

+0

我決定做類似如下的事情:1)創建一個具有存儲庫和實體成員變量的「服務」類。實體成員變量只是我正在建模的對象(PO​​CO ??)的屬性。控制器將實例化服務並設置其存儲庫和實體值。然後它會調用服務的Add()方法。而且我正在使用Ninject也處理依賴關係。在重做我的應用程序以像這樣工作之前,有什麼想法? – user660734 2011-04-02 21:10:23

+0

在我看來,您應該有一個productService類,它包含對產品存儲庫和作爲私有成員的購物車的引用。 這些存儲庫的實例可以通過依賴注入來提供。 此類還應包含以產品和(目標)購物車爲參數的方法,查詢此產品是否在任何其他購物車中使用,並最終將產品添加到目標購物車。 – Frank 2015-11-06 10:31:26

0

如果您想要可擴展性,直接從GUI使用數據訪問對象是不好的做法。所以在你提到的例子中,我認爲你應該替換由支持業務操作的一些業務邏輯類直接讀取或寫入數據庫的存儲庫。

+0

定義的存儲庫模式是一種抽象。就我而言,它是實體框架的包裝。 – user660734 2011-04-02 20:22:55

8

我通常構建我的MVC解決方案,在某種程度上類似於如下:

  • X.Core
    • 一般擴展方法,記錄和其他非網絡的基礎結構代碼
  • X 。域
    • 域實體和庫
  • X.Domain.Services
    • 域名服務編排複雜的領域操作,如將產品添加到購物車
  • X.Application.Core
    • 應用邏輯(初始化(路線註冊,IoC配置等),Web特定的擴展,MVC過濾器,控制器基類,視圖引擎等)
  • X.Application.Models
    • 視圖模型類
  • X.Application.Services
    • 服務類,可以通過訪問周圍倉庫或域名服務,以及其他方式進行更新
  • 返回的ViewModels X.Application。網絡
    • 控制器,觀點和靜態資源

有些可以合併,但有它們分開使得它更容易找到的東西,以確保您層邊界得到尊重。

表示對製品車的典型控制器的動作可能是這樣的:

public virtual ActionResult ProductCart() 
{ 
    var applicationService = <obtain or create appropriate service instance> 
    var userID = <obtain user ID or similar from session state> 
    var viewModel = applicationService.GetProductCartModel(userID); 
    return View("Cart", viewModel); 
} 

一個典型的控制器行動將產品添加到購物車因此可能是這個樣子:

public virtual ActionResult AddProductToCart(int productID) 
{ 
    var domainService = <obtain or create appropriate service instance> 
    var userID = <obtain user ID or similar from session state> 
    var response = domainService.AddProductToCart(userID, productID); 
    return Json(new { Success = response.Success, Message = response.Message }); 
} 
+0

謝謝,但我不確定這是否回答我的問題。 – user660734 2011-04-02 19:56:43

+0

更新了一些代碼示例,以說明何處放置邏輯的基本想法 - 希望這有助於:) – 2011-04-02 20:23:27

+0

看着你的項目結構我不確定我直覺地理解什麼地方。這可能更多與MVC有關,但它不會*感覺*合乎邏輯。 – flesh 2011-04-02 20:50:08

0

我試圖學習與ASP.Net MVC和正在讀史蒂夫桑德森的書。 我很困惑的一件事是放置業務邏輯的地方是 ?

在模型中(MVC中的M)或域圖層。這些是一組獨立的類型(最好在單獨的項目中),它們表示域模型,服務和存儲庫。

1

現實情況是,這個答案沒有銀彈,而且它的確是一個背景問題。我喜歡儘可能地分離事物,如果您仔細考慮,業務邏輯就是應用中的另一層。

我開發了一個BDD風格的決策引擎,並通過NuGet將其作爲OSS項目發佈。該項目名爲NDecision,您可以在NDecision project home page上閱讀。

NDecision使決策樹業務邏輯實現起來相當簡單,如果您是Gherkin語法和Fluent編碼實踐的忠實粉絲,那麼您就會在家使用它。下面的代碼快照來自項目網站,並演示如何實現業務邏輯。

NDecision example code

這可能不是你的解決方案,但這個想法是,如果你已經有了一個裝配您的域模型 - 一個偉大的想法,並在另一個答案前面建議的通常做法,沒有理由爲什麼你不能在你的「決策樹」上再安裝一個程序集。爲了將邏輯分離成一個獨立的層,NDecision就是爲了這一點而編寫的。

希望這會有所幫助。