零基礎ASP.NET Core WebAPI團隊協作開發
相信大家對“前後端分離”和“微服務”這兩個詞應該是耳熟能詳了。網上也有很多介紹這方面的文章。我這裡提這個是因為接下來我要分享的內容和這個有些關聯。
隨著前端應用場景的繁榮,使用者體驗需求的提高,原先傳統的後端渲染頁面返回給前端展示的模式面臨挑戰。後端工作除了處理資料邏輯還得適應介面UI的業務,越來越不堪負重。前端的重要性逐漸體現出來,在這種情況下使用前後端分離模式開發的逐漸增多。
前端框架(比如Vue/Angular/React)的發力,大廠的推廣使用,前後端分離已經很成熟。包括傳統資訊化這塊以前使用傳統WebMVC模式的開發的BS應用有些都逐步轉為前後端分離模式。特別是開發人員分工之後專注做好各自的工作,效率更高,做出來的產品也就更好。
一、應用場景
1、瀏覽器端(Vue/Angular/React)+服務端API
2、桌面客戶端(mfc/winform/wpf)+服務端API
3、移動客戶端(各種App/App內建瀏覽器)+服務端API
4、其他終端(大資料展示平臺/報表展示平臺)+服務端API
客戶端越來越強調輕量化,互動體驗,不在滿足於能用。服務端端只管提供API資料,這樣業務邏輯大多在服務端處理,隨著需求增加服務端的模組會越來越多。但是有些介面是共用的,有些是根據業務變動的,還有的API新舊版本過渡更新替換等等是服務端api要考慮的事情。設計好API開發框架面靈活應對這麼多場景就很有必要了。
原先可能會做一個單體式應用,把所有用到的介面都加進去。但這樣粒度很粗,如果某個場景下只使用了部分介面,那也得把這整個應用部署,無法做到按需新增。還有就是可能要修改其中部分方法,需要整體重新編譯釋出。這都存在可能影響其他模組的風險。
服務端任務量大了,怎麼分工?這個時候單體明顯已經不適用了。這裡就引出了微服務。對微服務可能每個人有不同的理解,但有一點是有共識的,就是把一個大的單體式應用根據功能模組拆分,這樣粒度細分之後很多介面就可以共用。之後的修改增加都是可以按需釋出部署,區域性出現問題不會影響整體。
這個服務的粒度怎麼拆分也是需要慎重考慮的問題。除了功能拆分還得考慮人員匹配。
案例場景:一個系統有10個子系統(模組),每個子系統(模組)又有10個功能,每個功能再具體又可能有20個左右的方法程式碼。
這個案例,最後大概有2000個方法程式碼。
如果開始安排10人的團隊開發,中途因為專案緊急再增加了10個人進來,總共變成了20人,專案組怎麼做才能快速適應這種人員變動。
有時候不是人越多越能做好事情,在人員增加情況下除了增加溝通協調成本,實際情況會遇到新加的人蔘與進來的門檻很高,不能快速著手展開工作,有時候還會出現不知道從何入手的困境。這就是因為拆分的不合理,任何的改動可能會影響到他人。這樣雖然為了趕進度加人了,但實際的效果卻不是很理想。
二、功能拆分分析
怎麼拆分這有兩個極端例子
1、粒度最粗,全部在一個解決方案(極端例子,類似單體式應用,適合一人開發)
2、粒度最細,細分到每個方法一個解決方案(極端例子,實際肯定不會這樣做)
實際專案中功能拆分就是在這兩個極端情況之間找適合的平衡點。具體拆分到多大的粒度,這個就只能是根據具體專案情況具體分析了。但是微服務可能是建議往細的方向拆。
如果是專案型的會發現如果拆的太細,上線一套系統要帶N個介面,運維實施都很麻煩;如果是做平臺型的產品可能就是有限的幾套系統,不會隨著專案鋪開太多定製化。也就沒有了專案型裡面的經常部署實施等繁瑣的問題。
比如上面的案例,一般都是先根據子系統拆分,具體到每個子系統,有一人或多人開發也有後期臨時加入的情況。每個子系統一套介面還是比較合適的。
實際情況專案型比較多,考慮實施運維情況拆分的粒度不會太細,讓實施去部署太多業務介面會把他們逼瘋。如果有和我類似情況的下面的方案提供了一種解決辦法。開發時候可以橫向任意擴充套件,新加入的人員分配任務清晰,不用擔心有耦合衝突。釋出部署也不會因為粒度太細,增加部署工作量。總結就是外掛式開發,微服務部署。
我們都知道vs裡面建立一個解決方案,兩三個開發人員在同一個解決方案裡面開發,只要協調好還行,如果再加入人員,參與的開發人員一旦多了,就算分工好做各自模組,但還是會存在一個些衝突,比如增加檔案,增加引用等等都會引起專案檔案或者解決方案檔案衝突問題。而且這種情況程式碼許可權還不好細分控制。
最好的方式是每個開發人員做的事情都在自己的解決方案裡面,只要是公共使用的引用協調好大家使用統一的版本,其他的自己完全可控,完全不用擔心影響他人,或者他人的修改影響自己。
大家可以看下這個 https://github.com/dotnet/corefx/tree/master/src,如圖1。
圖1
這是dotnet基礎庫的原始碼,每個基礎類庫都是單獨一個解決方案維護,隨便點一個進去看下,如圖2
圖2
每個類庫都有獨立解決方案檔案。
微軟肯定有更好的方式去管理,但從這裡可以看出,獨立開發維護的優勢。
三、介面專案準備
前面分享過一篇《零基礎ASP.NET Core MVC外掛式開發》的文章,那邊文章其實也就是強調團隊開發的時候能做到儘量獨立,可以橫向擴充套件,專案靈活變動增加開發人員可以快速參與,開發之後能彙總到一個個的子系統,最後完成整體開發。在這裡API的開發也可以使用類似方案,因為API沒有檢視部分,處理起來比MVC簡單。
接下來重點介紹該方案在API開發中的使用。開始這部分內容之前先簡單介紹我這邊API專案開發總結的兩個共性問題:
1、使用swagger顯示API文件(nuget 引用 Swashbuckle.AspNetCore)
因為API是沒有試圖的,為了視覺化,以及方便測試,使用swagger作為API的展示介面。具體使用看下面提供的demo程式碼
2、使用版本控制API版本號(nuget 引用Microsoft.AspNetCore.Mvc.Versioning)
版本控制對API也是同樣重要,看BAT大廠提供的API都是有版本控制的,要向他們看齊。實際應用中,程式不可能維持一套最新,有時候新舊版本需要過渡,所以需要有版本來區分。這裡使用微軟提供的版本控制。具體使用看下面提供的demo程式碼
這兩個使用這裡就不細說了,穿插下面主題做些簡單介紹,具體看案例demo就可以。
四、介面外掛式開發
回到我們的主題,這裡重點介紹下一個子系統(模組)任務拆分與人員分工
專案組接下一個專案,一般有個開發組長,著手模組劃分並且開發任務分工
組長(公共部分介面+核心功能模組介面)
組員1:細分的模組外掛1介面
組員2:細分的模組外掛2介面
組員3:細分的模組外掛3介面
......
......
對於的解決方案結構,具體命名自己可以根據喜好自己自定義。
Agile.ModuleName.API 如下圖3
Agile.ModuleName.Plug1.API 圖下圖4
Agile.ModuleName.Plug2.API
Agile.ModuleName.Plug3.API
......
......
圖3
圖4
Demo使用的是vs2019,Asp.net core 2.1
注意:如果一個模組裡面介面比較多,一個解決方案裡面不適合團隊開發。所以對這種介面功能比較多,拆成各個外掛方便團隊開發,最後釋出的時候合併到一起。但是如果這個模組介面不是很多,就沒必要過度設計為了外掛化而拆開。
每個獨立開發的都是vs裡面建立的標準ASP.NET Core WebAPI專案,這裡主專案和各個外掛專案沒有從屬關係,完全平等API專案開發,最後只是可以匯合到主專案作為一個站點發布交付。各自獨立除錯執行各自開發功能模組,測試沒問題釋出彙總到主專案,部署執行,之後哪個介面問題只需要找到對應的模組修改,完全隔離開,不用擔心修改會影響其他正常使用的模組。
主專案解決方案結構,如圖5
圖5
v1,v2裡面的是有版本控制的,放在外面的就不需要版本控制。
還有Extensions資料夾裡面兩個類也是為了版本的顯示做處理,具體看Startup.cs裡面程式碼,如圖6
圖6
搭建好之後,主專案執行,選擇v1版本顯示如圖7
圖7
如果選擇v2,顯示如圖8
圖8
通過上面兩個切換,應該看到不管選擇v1還是v2下面不受版本控制的都會顯示。
如果把圖4的程式碼註釋掉,看下執行效果,如圖9
圖9
顯示就這樣,不能根據swagger選擇,直觀的顯示是v1還是v2。這個就是RemoveVersionFromParameter和ReplaceVersionWithExactValueInPath兩個類的作用。
這兩個類的程式碼如下
public class RemoveVersionFromParameter : IOperationFilter { public void Apply(Operation operation, OperationFilterContext context) { if (operation.Parameters.Count > 0) { var versionParameter = operation.Parameters.FirstOrDefault(p => p.Name == "version"); operation.Parameters.Remove(versionParameter); } } } public class ReplaceVersionWithExactValueInPath : IDocumentFilter { public void Apply(SwaggerDocument swaggerDoc, DocumentFilterContext context) { swaggerDoc.Paths = swaggerDoc.Paths .ToDictionary( path => path.Key.Replace("v{version}", swaggerDoc.Info.Version), path => path.Value ); } }
到這裡主專案API執行正常,接下來看下外掛專案API。
外掛1專案結構,和主專案類似,如圖10
圖10
單獨執行下這個外掛1專案,效果如圖11
圖11
這裡作為外掛API專案同樣有一點要注意,不要出現和其他外掛或者主專案同名的路由(version,controller,action三個完全一樣,分工之後各自命名規範估計這種情況也不會出現,主要還是注意避免合併之後路由重名問題)。
這裡先把外掛1編譯的dll放到主專案的執行目錄來,如圖12
圖12
並且在主專案的Startup.cs裡面增加這段程式碼,如圖13
圖13
執行看下效果,如圖14
圖14
匯合成功,外掛1的API能展示出來,測試也正常,測試就不截圖了。
同理,外掛1,外掛2...等等也是一樣處理。開發階段,各自開發的功能都是可以獨立除錯執行的。有沒有主專案對各自開發的不影響。
五、問題總結
如果外掛專案裡面引用了一個第三方的程式集,如圖15
圖15
引用一個測試類庫,在Plug1NoVerController的Get方法裡面寫一個測試程式碼,如圖16
圖16
在外掛專案單獨測試,執行正常。
再把外掛1相關檔案拷貝到主專案,這時候多了個外掛專案自己引用的OtherLib.dll,如圖17
圖17
正常執行,如圖18
圖18
測試下剛才外掛1裡面用到OtherLib類的介面,看效果如圖19
圖19
汗,居然報錯了,提示FileNotFoundException,但是看上面的錯誤資訊截圖提示找不到OtherLib.dll檔案。OtherLib.dll這個檔案明明在這個目錄有的。查了相關資料都說是.net core的載入機制變了,但還是沒理解透徹,不知道.net core3.0會不會解決這個問題。希望有大神看到可以解惑下這個問題。不過這裡我使用一種方式可以解決這個報錯,在主程式這裡加這段程式碼。在註冊外掛專案之前,遍歷所有dll,做一次載入就可以了。如圖20
圖20
需要在註冊外掛之前,把所有dll檔案這樣載入一遍,就可以了。
再執行,測試就正常了,如圖21
圖21
六、釋出執行
各個獨立開發的外掛API,各自獨立開發除錯正常之後,釋出出來。
好了,外掛1,外掛2...等等各自都開發好了,各自模組除錯沒問題,最後彙總到主的專案來,基本也就沒什麼問題了,並且還可以作為一個站點部署。
這裡的一個站點只是一個介面服務,不要理解成一個系統就這一個介面服務,雖然可以這樣做,但不建議,部署還是各個子系統一個服務,這樣數量也不會很多。這裡是指在開發階段對一個子系統(模組)的N個介面做開發方面的分工獨立開發除錯。
子系統(模組)有N個介面,開發分工如下:
主外掛,外掛1,外掛2,外掛3...
全部彙總到主外掛的釋出目錄,或者手動拷貝,最後提供一個完成的子系統介面釋出版本,目錄如圖22
圖22
同樣命令列執行,或者宿主到iis,這裡命令列執行,如圖23
圖23
瀏覽器開啟,如圖24
圖24
直接swagger測試各個介面,正常。
獨立外掛化開發,微服務釋出部署。
希望你看了之後有點收穫,程式碼程式下面附件提供