時隔一年,繼續我們的Apworks框架之旅。在接下來的文章中,我將逐漸向大家介紹如何在Visual Studio中結合Apworks框架,使用ASP.NET Web API和MVC來開發面向經典分層架構的應用程式。在這一講中,我們首先了解一下分層架構的各個“層”,以及所涉及的Visual Studio專案,然後,我們從領域模型開始,在Visual Studio中開始我們的應用程式開發之旅。
說明:雖然現在微軟已經發布了Visual Studio 2015,但為了照顧廣大的老版本使用者,本文及後續文章都會以Visual Studio 2013 with Update 4作為開發工具進行介紹。此外,在某些場景中,會需要用到Visual Studio 2013 Ultimate的部分功能,所以,如果您所使用的Visual Studio不是Ultimate版本的話,您將無法動手實踐某些案例,但您仍然可以通過閱讀文章來獲取所需要的知識。
Apworks的近況
已經有一段時間沒有向大家介紹Apworks框架的相關內容了,在最近的半年中,我對Apworks做了一些小的重構,具體內容如下:
- 將支援的.NET Framework升級到4.5.1
- 開始在IEntity介面上支援泛型ID,這也就意味著在經典分層架構的Apworks應用中,實體鍵可以開始支援多種原始資料型別了(組合鍵目前仍不支援),比如整形。這一改動不會對已有的框架產生任何影響,預設的實體鍵型別仍然是Guid
- 開始在Unit Of Work的具體實現,也就是RepositoryContext上支援非同步Commit的操作:可以使用CommitAsync來進行非同步提交。後續版本會支援更多的非同步方法
- 更新所依賴的第三方框架到最新版本(當然,在寫這篇文章時,這些第三方框架或許又有了版本更新)
- 改善了NHibernate Repository的實現
- 效能優化
您可以直接點選 https://github.com/daxnet/Apworks 進入Apworks框架的開源主頁,也可以使用以下命令獲取Apworks的原始碼:
git clone https://github.com/daxnet/Apworks.git
案例:個人便籤應用
我又一次試圖從一個應用案例開始向大家介紹整個事情的來龍去脈,希望能夠讓大家看清楚並瞭解到問題的本質。我記得之前也有很多文章我也是舉了不少例子,有的文章把例子講解完了,有的又是半途而廢,虎頭蛇尾。好吧,不管怎麼樣,沒有案例就無法一步步地將問題解釋清楚。畢竟理論也是需要跟實踐相結合的。
這個案例是一個個人便籤應用。剛開始的時候,我把這個小標題稱為《案例:一個簡單的個人便籤應用》,思索之後將“一個簡單的”五個字去掉,我想,簡單的東西不是大家想要的,簡單的東西大家都會做,聽起來似乎甚至不需要任何框架和工具的輔助,就能簡簡單單地把問題解決掉。我想向大家介紹的是一個完整的企業級應用,它不僅應該實現基本的領域邏輯,更應該包含諸如安全、效能等各個方面的內容,所以,綜合起來,這事情就簡單不了。
認識我的圈內朋友應該都知道我自己開發了一個基於雲的個人筆記系統Cloud Notes,也有一些文章介紹Cloud Notes的技術和開發過程。不錯,現在我打算使用的這個案例,它的業務背景跟個人筆記系統很像,但為了介紹技術部分,我會讓其業務變得更為簡單,也會介紹一些實現RESTful服務的最佳實踐,因此,該案例會在技術架構層面與Cloud Notes類似,但也會有些細節上的差異。總而言之,儘量以簡潔的形式來說明問題。
本案例涉及的部分包括使用者和許可權,從業務上看,每個使用者可以管理自己的便籤,內容就這麼多。太複雜了會讓人覺得頭暈目眩,也會降低本文的可讀性。OK,讓我們給這個案例起個名字,就叫EasyMemo吧。
理論:分層架構與技術選型
在我以前的部落格中,少不了對分層架構的介紹,尤其是在介紹領域驅動設計的時候,還介紹了與之異構的基於事件的命令查詢職責分離(CQRS)架構。本案例採用經典分層架構進行開發。在此,我覺得還是有必要把架構圖再簡單畫一下,並且標註我們將要使用的微軟技術。這樣做一方面可以讓大家瞭解到我們使用了哪些技術,另一方面,在後續的介紹中,也可以讓大家看到,我們目前是在討論整個架構的哪個部分。請參見下圖:
可以看到,在整個案例的介紹過程中,我們將會使用Entity Framework 6作為資料儲存ORM,後臺資料庫選用Microsoft SQL Server,領域模型層適配Apworks框架,應用層任務協調使用Apworks框架,而通過ASP.NET Web API 2向外界提供RESTful服務。表現層採用ASP.NET MVC 4加上AngularJS實現,當然會用到Twitter Bootstrap的一些特性,畢竟在標準的ASP.NET MVC模板中,預設安裝了Bootstrap的包。
基本架構就這樣,接下來,讓我們一起動手開始在Visual Studio 2013中搭建我們的EasyMemo專案吧。
實踐:開始搭建解決方案
開啟Visual Studio 2013,當然,目前我們還不需要使用Ultimate版本,因為解決方案的搭建過程不會涉及任何與Visual Studio 2013 Ultimate相關的特性。為了能讓解決方案中各專案的組織更為合理,建議首先在Visual Studio 2013中新建一個空白的解決方案,.NET Framework版本請選擇4.5.1,因為今後要用的Apworks框架是基於4.5.1的:
單擊“確定”按鈕後,Visual Studio就會在【解決方案資源管理器】中顯示一個空白的解決方案。接下來,我們就相繼往該解決方案中建立以下新專案:
- EasyMemo.Common:提供包括公共型別以及基礎結構層的那些可以適用於其它各層的型別和元件
- EasyMemo.Domain:包含領域模型的型別,以及這些型別的擴充套件方法
- EasyMemo.Repositories:倉儲實現庫,提供與領域模型物件倉儲相關的型別定義以及實現
- EasyMemo.Services:一個ASP.NET Web API應用程式,用以向外界提供RESTful服務。在【新建專案】對話中選擇【Visual C# –> Web】分類,在該分類中選擇【ASP.NET Web應用程式】,在彈出的【新建ASP.NET專案】對話方塊中,選擇【Empty】,在【為以下物件新增資料夾和核心引用】分組中,選擇Web API:
- EasyMemo.Web:EasyMemo的主頁網站,向使用者提供操作介面,接收使用者請求,並將請求轉發到RESTful服務。在【新建專案】對話中選擇【Visual C# –> Web】分類,在該分類中選擇【ASP.NET Web應用程式】,在彈出的【新建ASP.NET專案】對話方塊中,選擇【MVC】:
建立完成後,EasyMemo的解決方案中應該包含如下5個專案,每個專案中都只包含了Visual Studio專案模板自帶的預設型別:
為了能夠在編譯整個解決方案的時候,讓Visual Studio自動下載每個專案所依賴的NuGet包,強烈建議在EasyMemo解決方案上單擊滑鼠右鍵,選擇【啟用NuGet程式包還原】選項:
現在,我們就從領域模型的設計開始,一步步地完成整個應用程式的開發。
邁向領域建模的第一步
首先,在EasyMemo.Domain專案上,單擊滑鼠右鍵,選擇【管理NuGet程式包】,在彈出的對話方塊的【搜尋聯機】文字框中,輸入關鍵字【Apworks】,然後在程式包列表中選擇【Apworks】並單擊【安裝】按鈕:
在安裝時會提示許可協議對話方塊,單擊【我接受】按鈕即可。
然後,在EasyMemo.Domain上再新增一個AggregateRoot抽象類,使其實現Apworks中的IAggregateRoot介面:
using System; using Apworks; public abstract class AggregateRoot : IAggregateRoot { public Guid ID { get; set; } }
再新建一個Account類,使其繼承AggregateRoot類,它表示在EasyMemo整個應用程式中的“使用者賬戶”的概念,為了今後的實現更為方便快捷,Account類僅提供以下屬性:
/// <summary> /// 表示EasyMemo中“使用者賬戶”的概念 /// </summary> public class Account : AggregateRoot { /// <summary> /// 獲取或設定賬戶名。 /// </summary> public string Name { get; set; } /// <summary> /// 獲取或設定賬戶密碼。 /// </summary> public string Password { get; set; } /// <summary> /// 獲取或設定郵箱地址。 /// </summary> public string Email { get; set; } /// <summary> /// 獲取或設定顯示名稱。 /// </summary> public string DisplayName { get; set; } /// <summary> /// 獲取或設定賬戶建立日期。 /// </summary> public DateTime DateCreated { get; set; } /// <summary> /// 獲取或設定最近一次登入日期。 /// </summary> public DateTime? DateLastLogon { get; set; } }
編譯EasyMemo.Domain,編譯通過,表示我們已經正常安裝並引用Apworks程式包了,可以繼續對領域模型進行設計了。在下一講中,我將介紹EasyMemo領域模型的設計。