2012年11月18日 星期日

ASP.NET MVC 專案分層架構 Part.4 - 抽出 Model 層並建立為類別庫專案

2014-12-02 補充說明:
這一系列的文章並不適合初階及中階的開發人員,如果你是程式開發的初學者或是 ASP.NET MVC 初學者,甚至是開發經驗少於兩年的開發人員,請馬上離開此篇文章。

經過了前面三篇的過程,我們使用了 Repository Pattern 把有關資料存取的部分從 Controllers 程式中抽離出來,而現在我們接下來要做的是把專案中有關資料存取的部分給抽出來,另外建立一個 Project 來放置這些抽離出來的資料存取層。

把 Model 層從 Web 專案中抽離出來,這表示 Web 專案只關注於資料呈現以及系統控制流程的部份,凡是要跟資料打交道的存取操作就不會出現在 Web 專案中,讓兩個專案有各自的職責與關注的事物。

 


建立 Models 專案

回顧上一篇完成之後的專案情況,

image

上圖中用紅色線框起來的部分就是我們要抽出來另外建立為專案的部份,廢話不多說,就馬上在同一個方案(Solution)下新增專案,

image

選擇建立的專案類別為「類別庫」,並且修改名稱,名稱不要亂取,通常我會以「Models」為結尾字,方便識別,

SNAGHTML35b364d

而原本的 Web 專案,我會建議也做修改,結尾字使用「Web」或是其他可以表示此為 Web 專案的字,一般來說很少在專案做到一半的時候去修改專案名稱,因為一修改的結果就是要跟著修改程式中的命名空間,

image

此時重新建置網站一定會出現問題,因為就如同前面所說,很多命名空間都沒有跟著修改,但我們還是先把 Web 專案中的 Model 相關事物給移到 Models 層專案。

接著在新建立的 Models 專案中新增 ADO.NET 實體資料模型,

image

接著就是把 Web 專案 Models 目錄中的 Interface 與 Repository 給搬到 Models 專案下,

image

已完成搬移到 Models 專案下

image

把原本 Web 專案下的 Models 相關事物給搬移到 Models 專案後,就可以把 Web 專案下的 Models 目錄給移除,

image

接著下來就是要開始整理兩個專案內的相關程式碼,因為我們原本在 Web 專案下的 Models 相關程式的命名空間就已經是使用「Mvc_Repository.Models」,所以 Interface 與 Repository 等相關程式搬移到 Models 專案下就不必去修改命名空間了,此時先對 Models 專案做重新建置的動作,先確保 Models 專案的建置是沒有問題的。

image

 

 

Web 專案加入方案下的 Models 專案參考

因為已經把 Models 給抽出去另外獨立成一個專案,所以原本的 Web 專案就必須加入同一個方案下的 Models 專案參考,

image

顯示「參考管理員」視窗後,

(1)選擇方案 > 專案 項目

(2)勾選 Mvc_Repository.Models 專案

(3)最後點選確定

SNAGHTML39128c7

加入 Models 專案參考後,可以在 Web 專案的參考下可以看到「Mvc_Repository.Models」,

image

接下來就是重新建置整個方案,並且全部重建成功,

image

但是重新建置全部成功並不代表網站可以正常執行,因為我們剛剛有修改原本 Web 專案的命名空間與組件名稱,所以就必須把 Web 專案中的程式做個修正,需要做修正的 Web 專案程式如下:

Global.asax

image

 

Controllers 目錄:

HomeController.cs

image

CategoryController.cs

image

ProductController.cs

image

 

App_Start 目錄:

BundleConfig.cs

image

FilterConfig.cs

image

WebApiConfig.cs

image

RouteConfig.cs

image

 

 

調整 Models 專案的 EDMX 設定

把 EDMX 屬性中的「中繼資料成品處理」調整為「內嵌在輸出組件中

image

 

再來就是把 Models 專案裡 App.Config 的 ConnectionString 複製到  Web 專案 Web.Config 中,

<add name="TestDBEntities" 
connectionString="metadata=res://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl;
provider=System.Data.SqlClient;provider connection string=&quot;
data source=192.168.137.228;initial catalog=TestDB;persist security info=True;user id=testdb;password=test1234;
multipleactiveresultsets=True;application name=EntityFramework&quot;" 
providerName="System.Data.EntityClient" />

Models 專案 的 App.Config

image

copy and paste to … Web 專案的 Web.Config

image

 

經過以上的修改至之後就大致完成了,接著就是重新建置方案,方案建置成功後就執行網站來驗收修改成果,

首頁(Home/Index)

SNAGHTML4347582

Category List(Category/Index)

image

Product List(Product/Index)

image

PS.
這邊所呈現的頁面樣式與「ASP.NET MVC 專案分層架構 Part.1 初學者的起手式」這一篇裡面原來呈現的樣式有很大的不同,這是因為我有套用 Twitter Bootstrap 樣式的關係。

 

大部分的專案開發都需要先規劃好專案的架構內容,要劃分哪幾層,這些層各自有何職責、要做什麼的處理;就一般專案開發而言,專案開發到一段時間過後才開始做抽離分層的動作,這樣的情況是比較少見,因為對於專案的影響比較大,除非不得已,不然會建議另外重新開啟一個新的方案來做各層的建立與規劃。

 


其實這一篇算是比較沒有什麼,把 Model 層給抽出來建立為單一 Project 這件事情不見得每個專案都要這麼做,看專案的規模大小,小型專案就不見得要做這樣的獨立分層專案,只需要在 Web 專案中做好分層規劃就好,而大型專案又是多人開發的情況,真的會建議要做獨立分層的規劃,其目的在於避免開發時的混亂。

之前曾經開發過一個專案,專案規模算是蠻大的,而且是好幾人同時進行開發,一開始只有在 Web 專案中做分層規劃,隨著專案的持續開發,漸漸的越來越多 Model 的加入,甚至是越來越多 ViewModel 的建立,開發人員也跟著越來越多,因為只有切出 Repository 來處理所有的資料存取與商業邏輯操作,再加上沒有一個明確的開發規範,這時候整個專案就混亂到不行,就可以看到開發人員恣意的在 Model 的 Repository 加入自己要用的 method 而不管什麼物件的單一職責,當然這樣的混亂並無法用獨立分層專案的方式就可以解決,但假如一開始就有做到這樣的規劃,至少在 Web 專案這邊可以比較單純,而 Model 層的 Repository 與 ViewModel 的混亂可以再做其他的規劃來解決。

這一篇就先說到這裡。

 

系列文章下一篇:

ASP.NET MVC 專案分層架構 Part.5 - 建立 Service 層

 

延伸閱讀:

The Will Will Web  - 關於 Entity Framework 獨立放在 DAL 專案的注意事項

 

以上

4 則留言:

  1. 您好:
    最近單位有個MVC專案,
    成員將model切出去成為獨立專案,
    不過在原本的mvc專案於增加檢視時,
    發現無法像當初Model在同一專案時,
    可以在《加入檢視》對話框中的[模型類別]下接選單選到Model的poco名稱,
    不知道是否在Model切出去後,是否於原本的MVC專案還要再做什麼設定?
    可否請您指點迷津,謝謝~

    回覆刪除
    回覆
    1. 原本的 MVC 專案有加入切出去 Model 專案的參考嗎?
      再來就是 Model 專案的命名空間名稱,
      我想你有看過我這一系列的文章,應該可以比對出這些細節.

      刪除
  2. 您好:
    我照著步驟做最後出現:
    找到多個與名為 'Home' 的控制器相符的類型。如果服務此要求 ('{controller}/{action}/{id}') 的路由沒有指定命名空間以搜尋符合該要求的控制器,就會發生這個情況。在這種情況下,請呼叫可接受 'namespaces' 參數的 'MapRoute' 方法的多載來註冊此路由。

    'Home' 的要求找到以下符合的控制器:
    MVC_Repository.Controllers.HomeController
    MVC_Repository.Web.Controllers.HomeController
    ----------------------------------------------------------------------
    我google查到的解決方法是在RouteConfig的routes.MapRoute加上
    namespaces: new[] { "MVC_Repository.Web.Controllers" }
    不過無效,最後我試著將HomeController移出專案,結果竟然Home的畫面有出來,可是明明Controller裡面已經沒有HomeController了,
    ProductController也是相同的情況,只是把命名空間改成MVC_Repository.Web.Controllers,卻出現這種好像複製出第二份Controller狀況,
    希望可以指引方向,謝謝

    回覆刪除
    回覆
    1. 看來是命名空間名稱的問題
      因為不清楚你的實做步驟與程式碼內容
      所以就直接看範例專案的程式吧
      https://kevintsengtw.blogspot.com/2015/04/aspnet-mvc-twmvc18.html

      刪除

提醒

千萬不要使用 Google Talk (Hangouts) 或 Facebook 及時通訊與我聯繫、提問,因為會掉訊息甚至我是過了好幾天之後才發現到你曾經傳給我訊息過,請多多使用「詢問與建議」(在左邊,就在左邊),另外比較深入的問題討論,或是有牽涉到你實作程式碼的內容,不適合在留言板裡留言討論,請務必使用「詢問與建議」功能(可以夾帶檔案),謝謝。