1. 程式人生 > >應用程式框架實戰三十八:專案示例VS解決方案的建立(一)

應用程式框架實戰三十八:專案示例VS解決方案的建立(一)

  進行專案開發的第一步,是創建出適合自己團隊習慣的VS解決方案,雖然我已經提供了專案示例,但畢竟是我建立的,你直接使用可能並不合適,另外你如果嘗試模仿重新建立該示例,中間可能碰到各種障礙,特別是專案間的依賴關係。

  本文的目的是幫助.Net架構初學者能順利搭建起適合自己的VS解決方案,我會在本文演示曾經用過的幾種不同風格的目錄結構,你可以根據自己的習慣選擇一種並自行修改。

  本系列假定你已經熟悉如何建立.NET類庫等基礎知識,並具有.Net開發經驗,我不會詳細到每一個細節。如果你是.Net初學者,尚未開發過任何實際專案,對你的建議就是關閉本頁面,去買本書打好基礎,需要提升時再來。

影響VS解決方案結構的因素

分層

  VS解決方案的建立,與你採用的分層方式密切相關,我在之前的文章已經簡單介紹過單層架構和三層架構,本文采用DDD分層架構進行演示,說明專案示例Applications.Managements是怎樣創建出來的,並且可以怎樣簡化。

  我們平時所說的分層,屬於邏輯分層,它按照一定的邏輯層次分離關注點,以便更好的組織程式碼結構,方便維護。

  物理分層,是將不同的程式碼部署到不同的伺服器,以提供更高效能和安全性,如果對邏輯分層和物理分層的關係感興趣,請參考《C#企業應用開發藝術-CSLA.NET框架開發實戰》一書。

  對於邏輯分層,只要將程式碼分離到不同區域即可,可以按照不同的抽象粒度來組織程式碼,比如類級別、目錄級別、程式集級別。

  目前普遍採用的是程式集級別進行分層,即不同層的程式碼放到不同的程式集中。

  如果期望減少程式集,可以僅建立一個類庫,採用目錄級別的劃分方式,在一個類庫中建立不同層的資料夾,各目錄放置各層的程式碼。

  類級別粒度將不同層的物件合併,通過方法的形式分離各層程式碼。

  通過程式集方式分層有諸多好處,比如清晰度、複用性等,我將採用程式集方式進行演示,建議你在專案上也儘量採用這種方式。

功能模組

  另一個影響VS解決方案建立的因素是功能模組的劃分。

  對於一個業務系統,我們不僅要分層,而且還要劃分功能模組,以便對較大的業務問題進行分解,從而降低複雜度,同時在解決某個特定模組的問題時,減少其它模組的干擾。

  對於領域層,我目前的方式是為每一個功能模組建立一個類庫專案,這樣做的好處是更方便複用,另外當我需要將這個功能模組分離出去也會更容易。

  當然,採用資料夾來分隔也同樣可行,這是兩種不同的風格,我會向你演示如何設計可以更方便的切換。

可複用能力

  對於一個稍大的專案,把特定業務模組、通用業務模組、通用技術類庫放在同一個VS解決方案中,VS解決方案上的專案可能會達到上百個,編譯速度將非常緩慢,導致很多不必要的麻煩。

  我之前已經多次提到,你可以把通用技術類和通用業務類從具體專案中分離出來,這樣可以供多個專案使用,每個專案擁有自己的VS解決方案,共享相同的應用框架,這樣維護會更容易,編譯速度也更快。  

  對於Applications.Managements專案示例,通用技術類庫已經抽取到Util解決方案中,Applications.Managements不包含通用性的純技術程式碼。

  我不會為你演示通用業務類的分離,因為程式碼示例太簡單。

其它因素

  不同的應用程式型別也會影響VS解決方案的建立,比如建立WPF智慧客戶端應用程式,需要將應用層建立為WCF類庫,這樣可以將應用服務直接開放出來供WPF呼叫。對於WPF+WCF的架構,我後續也會進行介紹,如何通過IOC切換本地呼叫和遠端呼叫,通過這個架構可以在開發時期採用本地方式呼叫,提高開發效率,部署時切換到WCF遠端代理。

  如果你採用了諸如SOA架構,需要切割子系統部署成服務,可能需要建立更多型別的專案和多個VS解決方案,這些架構也對VS解決方案的建立具有相當影響。由於本人在SOA方面經驗尚淺,待後續有更多經驗再進行分享。

VS解決方案建立實戰

  下面的步驟演示了我建立VS解決方案的習慣,你不一定要按我的步驟,只要最終達到你的要求即可。

建立表現層MVC專案

  開啟VS解決方案,我使用的是VS 2013,自帶了MVC4。

  建立MVC4專案,專案名稱為Applications.Presentation.Managements,解決方案名稱為Applications.Managements,MVC專案模板選擇“基本”。

  先來討論頂級空間的命名,即這裡的Applications,要點是儘量抽象。頂級空間名稱儘量不使用特定於專案或客戶的名稱,因為你做下一個專案時,需要大量更改名稱空間。我採用Applications,代表抽象的應用程式,任何專案都是應用程式。你也可以採用公司的名稱,比如你們公司簡稱為abc,那麼可以這樣Abc.Managements。

  Managements代表這是一個管理系統。Applications.Presentation.Managements說明它是管理系統的表現層,但為什麼不用Applications.Managements.Presentation,後面介紹到領域層時我會說明這樣做的原因。

  對於表現層來講,沒有其它層會呼叫它的API,所以我想保持表現層名稱空間的簡短,我耍了一個小技巧,將表現層的名稱空間改成了Presentation。

  右鍵單擊Applications.Presentation.Managements專案,選擇“屬性”,修改“預設名稱空間”為Presetation,如下圖所示。

  MVC建立完成後,會在根目錄留下一個packages資料夾,MVC專案也會新增packages.config配置,這玩意很有用,Nuget會幫你管理依賴的程式集及版本,當別人執行你的解決方案時缺少程式集,會自動下載還原。但我更喜歡自己手工管理,在Applications.Managements根目錄建立Libraries資料夾,我會把packages中必須的幾個dll複製進去,其它全部刪掉。

  當然,修改表現層預設名稱空間和刪除packages屬於我的個人習慣,介紹這個是方便你看我的程式碼,對於你自己的專案,完全沒必要這麼麻煩。

  編譯通過,繼續下面的步驟,後面再返回到表現層。

建立表現層擴充套件專案

  在Applications.Managements解決方案上右鍵,“新增”->“新建專案”,建立一個類庫專案,名稱為Applications.Presentation.Managements.Extensions。

  這個專案用來為表現層提供一些支援,比如業務元件的封裝。

  將它的預設名稱空間改成Presentation,方便表現層的呼叫。

  下面來考慮類庫輸出的DLL目標位置,預設是在bin\Debug\,表示DLL將輸出到類庫專案的bin目錄下Debug資料夾中。由於我們後續會建立更多的程式集,如果對輸出位置不進行統一,將導致每個輸出目錄都產生大量重複的DLL。

  右鍵單擊擴充套件類庫,選擇屬性,找到“生成”選項卡的“輸出路徑“,修改為..\Release\,如下圖所示。

  下面為Applications.Presentation.Managements專案新增Applications.Presentation.Managements.Extensions擴充套件專案的引用。

編譯通過,繼續下面的步驟。

建立應用層專案

  在Applications.Managements解決方案上建立類庫專案,名稱為Applications.Services,修改類庫輸出路徑為..\Release\。

  應用層是為表現層提供服務的,所以表現層Applications.Presentation.Managements需要新增應用層Applications.Services的引用。

  編譯通過,繼續下面的步驟。

建立基礎設施層專案

  DDD分層架構中沒有了資料訪問層的概念,被包含到基礎設施層中。

  基礎設施層是為其它各層服務的,按道理說,其它各層應該包含對基礎設施層的引用。

  但是,為了讓領域層變得更純淨,一般會應用依賴倒置原則,讓基礎設施層反過來依賴領域層。

  一些初學者會產生疑惑,這樣不是造成迴圈引用的死迴圈了嗎?下面談下我的看法,不一定正確,僅供參考。

  在《領域驅動設計》一書中,對基礎設施層的描述為:基礎設施層為各層提供通用的技術能力

  可見基礎設施層是一個抽象概念,諸如層超型別、公共操作類的封裝、資料庫的持久化,發郵件,發簡訊等操作,都是基礎設施層的範疇。

  在我的程式碼中,大量通用技術,都被封裝到Util相關的程式集中,如果需要合併VS解決方案,那麼所有的Util專案都是基礎設施層的一個組成部分。

  對於領域層與基礎設施層的引用關係,與基礎設施層中專案耦合性強弱有關,一般規律是:

  1. 領域層只引用基礎設施層中低耦合的專案,比如領域層可以引用Util.Core、Util.Domains,這些專案只包含對.NET本身類庫的引用,沒有外部依賴,也不需要任何配置,領域層依賴這些專案不會降低可複用性和可測試性等指標。
  2. 與領域層密切相關的高耦合基礎設施層專案,應用依賴倒置原則,先在領域層定義操作介面,由基礎設施層專案引用相關領域層專案,並實現該介面。比如倉儲代表聚合的集合,倉儲的實現依賴於特定資料訪問技術,甚至包含SQL語句,所以具有很高的耦合,且與領域層特定模組密切相關。如果領域層直接引用資料訪問實現的程式集,將嚴重降低領域層的可複用性,且更難測試。
  3. 與領域層關係不大的高耦合基礎設施層專案,應用分離介面模式,將操作介面與具體實現分離到基礎設施層的不同專案中。比如工作單元的介面IApplicationUnitOfWork,它與領域層基本沒啥關係,如果你的領域層只包含一個類庫專案,把IApplicationUnitOfWork放到領域層專案中也沒什麼問題,我之前一直是這樣乾的,但如果你的領域層包含多個專案,你應該放到哪一個專案中?單獨建立一個基礎設施層專案來放置這些介面會好一些。

(未完待續…

程式碼更新

  1. 更新了js中的一些Bug
  2. 由於專案上需要使用MYSQL,最近幾天摸索了EF操作MYSQL,遇到的一些障礙已解決,特將解決方案放出,供使用MYSQL的同學參考。

    a) MYSQL的樂觀離線鎖與SQL SERVER顯著不同,主要參考王剛的這篇:EF6 Code First 系列 (三):在MySql中使用和SqlServer一致的RowVersion併發控制。不過對於Sql Server,我還是使用IsRowVersion,畢竟這是大部分專案的主打。

    b) 通過一個簡單的Ioc配置,即可將Sql Server切換到MySql。

  c) MySql不支援Sql Server的schema,我使用.分隔MySql表名模擬schema,以保持與Sql Server的一致性風格,這需要一點EF對映技巧。

  3. codesmith程式碼生成模板已更新,調整了名稱空間,並增加了對mysql特定配置的生成。

  4. 資料庫備份中提供了一個MYSQL建庫指令碼。

QQ群

  應用程式框架交流QQ群1:386092459(已滿)

  應用程式框架交流QQ群2:376124781

  EasyUi交流QQ群:157809322

原始碼下載:(下載時順手推薦)

框架原始碼

資料庫備份

備註

  本來準備只用一篇來完成本文,不過太忙了,只有分幾次來寫,希望各位見諒,下次更新的時間會比較長。