不少關注我博客的朋友都知道我在2009年左右開發過一個名為Apworks的企業級應用程序開發框架,旨在為分布式企業系統軟件開發提供面向領域驅動(DDD)的框架級別的解決方案,並對多種系統架構風格提供支持。這個框架的開發和維護我堅持了很久,一直到2015年,我都一直在不停地重構這個項目。目前這個項目在Github上也得到了將近260的推薦數,很多對技術感興趣的朋友也一直與我保持着聯系和交流,甚至還有愛好者自發組成了技術討論群,專門討論分享Apworks框架。
然而,隨着軟件開發技術和.NET的發展,這個框架的設計和研發技術都逐漸過時,重構難度逐漸加大,很多由其本身支持的技術,比如MSMQ、NHibernate也都逐漸淡出人們的視線,相比之下,雲計算、微服務、大數據、跨平台等相關技術越來越多地引起了業界的關注,成功的案例也越來越多。如何基於雲平台(PaaS + IaaS)快速搭建高效、經濟、穩定、安全的軟件系統架構,成為了最近兩年的熱門話題。微軟也順應這樣的潮流,做出了很多的改變,就在短短的一到兩年時間,引領了.NET的跨平台,開源了諸多著名的項目,比如.NET、Core CLR、Roslyn、ASP.NET、Entity Framework、Powershell等等,並且開始接受並擁抱非Windows的操作系統,比如Visual Studio跨平台、Powershell跨平台、SQL Server跨平台、Visual C++支持多種編譯器等等。很明顯,原有的Apworks已經不再具備跨平台、雲友好、開發迅速的特質,為此,我下定決心重寫了Apworks。
全新的Apworks Core應用程序開發框架
新的Apworks Core也是開源項目,該項目依舊基於Apache 2.0許可協議,項目地址是:https://github.com/daxnet/apworks-core。目前仍然還在繼續開發階段,僅實現了原有DDD中的基本概念(實體、聚合、實體鍵、倉儲等),並針對內存並發字典(Concurrent Dictionary)、MongoDB以及Entity Framework Core完成了三種不同的倉儲實現,整個框架完全由.NET Core實現(目前提供net461和Net Standard 1.6兩種編譯),因此,可以使用在Windows的經典.NET Framework下,也可以使用在Linux的.NET Core中。不僅如此,針對ASP.NET Core Web API,Apworks提供了相應的整合與擴展,使得數據服務的開發變得非常簡單方便,這也是本文准備介紹的內容,相信在閱讀本文之后,你將更多地了解到Apworks Core的開放性和擴展性,並能體會到在.NET應用程序的開發生態圈中,Apworks Core將會給你帶來更多的幫助。
演練:使用Apworks Core快速開發數據服務
在開始我們的Apworks Core開發演練之前,請先完成以下准備工作:
- 安裝Visual Studio 2017,確保.NET Core和ASP.NET Core的開發功能已經正確安裝
- 將https://www.myget.org/F/daxnet-apworks-pre/api/v3/index.json以及https://www.myget.org/F/daxnet-utils/api/v3/index.json兩個package source添加到NuGet的package source中:
- 准備一個MongoDB的數據庫服務器,建議直接下載Windows版本的搭建在本地機器,也可以在Linux下直接運行mongo的Docker容器,省去了安裝MongoDB的步驟
- 如果希望能一起嘗試Visual Studio 2017的Docker功能,還需要確保安裝最新版本的Windows以及Docker for Windows。當然,完成本文的演練並不需要Docker
開發步驟
- 首先,新建一個ASP.NET Core的應用程序,名為CustomerService,通過Manage NuGet Packages添加對Apworks.Repositories.MongoDB以及Apworks.Integration.AspNetCore的引用。添加引用的時候注意選擇https://www.myget.org/F/daxnet-apworks-pre/api/v3/index.json這個package source:
- 在CustomerService下新建一個Models目錄,添加兩個類,名稱分別為Address和Customer,代碼如下:
public class Address { public string Country { get; set; } public string State { get; set; } public string City { get; set; } public string Street { get; set; } public string ZipCode { get; set; } } public class Customer : IAggregateRoot<Guid> { public Guid Id { get; set; } public string Name { get; set; } public string Email { get; set; } public Address ContactAddress { get; set; } } - 在Controllers子目錄下,新建一個Controller,取名為CustomersController,代碼如下:
public class CustomersController : DataServiceController<Guid, Customer> { public CustomersController(IRepositoryContext repositoryContext) : base(repositoryContext) { } } - 打開Startup.cs文件,在ConfigureServices方法中,加入以下代碼:
public void ConfigureServices(IServiceCollection services) { // Add framework services. services.AddMvc(); services.AddApworks() .WithDataServiceSupport(new DataServiceConfigurationOptions (new MongoRepositoryContext (new MongoRepositorySettings("localhost", "customer-service")))) .Configure(); } - 同樣在Startup.cs文件中,在Configure方法中,加入以下代碼:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { loggerFactory.AddConsole(Configuration.GetSection("Logging")); loggerFactory.AddDebug(); app.EnrichDataServiceExceptionResponse(); app.UseMvc(); } - OK, you’re all set! 完成之后,解決方案資源管理器中的項目結構如下,增加了一個Models目錄,以及一個CustomersController:
編譯運行
直接按下Ctrl + F5運行站點,站點起來后,你會發現瀏覽器打開的內容跟標准的新建的ASP.NET Core Web API項目無異,顯示的是由ValuesController的GET方法返回的兩個字符串。不用着急,打開Fiddler,我們簡單測試一下剛剛新建的Customer數據服務(注意替換一下URL,我本地服務運行在2238端口上):
- POST http://localhost:2238/api/customers
POST操作成功返回HTTP 201,同時在Response Body中返回了新建的對象Id。 - GET http://localhost:2238/api/customers
限於篇幅,此處就不針對所有基本的HTTP操作一一進行測試了。Apworks Data Service默認支持以下HTTP方法,當然,你可以隨意擴展:
- GET:獲取所有的對象,默認支持服務端分頁,每頁15條記錄,可以通過http://localhost:2238/api/customers?page=aaa&size=bbb這樣的格式來指定每頁大小以及需要獲取的頁碼
- GET {id}:http://localhost:2238/api/customers/{id}:獲取Id值為{id}的對象
- POST {id}:替換Id值為{id}的對象,替換成功則返回HTTP 204(No Content)
- PATCH {id}:更新id值為{id}的對象,Request Body需要符合Microsoft ASP.NET Json Patch的規范。更新成功返回HTTP 204(No Content)
- DELETE {id}:刪除id值為{id}的對象。刪除成功返回HTTP 204(No Content)
幾個亮點
- 開發和配置過程及其簡單,如上所述,五個步驟完成一個數據對象的數據服務開發。流暢接口(Fluent API)配置方式,使得數據服務的開發過程與已有ASP.NET Core Web API的開發過程具有相同的開發者體驗
- HTTP GET調用默認支持服務端分頁,分頁鏈接會通過HAL標記體現在返回結果中
- HTTP GET返回直接支持Hypertext Application Language(HAL,官方網站:http://stateless.co/hal_specification.html),返回Content-Type為application/hal+json。它是通過我的另一個開源項目https://github.com/daxnet/hal 實現的,HAL項目在.NET Core下完整、全面地實現了HAL規范,並且通過流暢接口(Fluent API)的方式,提供了較好的開發者體驗。通過Apworks Core開發數據服務時,開發者可以通過設定DataServiceConfigurationOptions參數,選擇是否需要HAL支持,還可以擴展HalBuildConfiguration類型,以實現HAL返回結果的自定義
- 倉儲實現可以選擇使用In-Memory Concurrent Dictionary、MongoDB以及Entity Framework Core,整個技術棧完全跨平台。如果使用Entity Framework Core,目前EF Core對SQL Server、PostgreSQL以及SQLite的支持都不錯,對於Oracle等也有相應的Provider支持,因此,可以選擇各種不同的關系型數據庫來基於Apworks Core快速實現數據服務
- 加入EnrichDataServiceExceptionResponse方法可以使得當錯誤發生時,數據服務的返回結果將包含更為准確的錯誤代碼和錯誤信息
對於三種目前支持的倉儲的使用方式、HAL返回結果自定義,以及數據服務的擴展這些內容,我今后再慢慢介紹吧,這里就不多說了。
總結
現在,Apworks Core僅僅是剛剛開始,接下來還有很長的路要走,單從數據服務和ASP.NET Core的整合這部分,還需要更加豐富的功能,比如API的幫助頁面、查詢條件和排序條件的指定等等。查詢條件的支持我打算使用我遷移的一個開源的.NET語法分析框架:Irony項目來完成。之后,我還是會像往常一樣,基於Apworks Core實現一個完整的應用案例,來演示Apworks Core各方面的功能。
另一方面,Apworks Core的項目分支策略和持續集成也是可以拿來分享的。我沒有開放Apworks Core持續集成系統,但任何人都可以通過項目的Github主頁了解到最新構建的狀態,也可以看到最新preview和release版本的package source。Apworks Core同時在Windows Server和Ubuntu Linux下完成編譯,編譯完全采用Powershell腳本完成,因此,對於Linux系統,需要首先安裝Powershell。這些內容我也會爭取抽空跟大家做介紹。
最后,還是那句話,大家多多交流,多提寶貴意見吧。我爭取做得更好。![]()
