【复杂系统迁移 .NET Core平台系列】之迁移项目工程
源寶導讀:微軟跨平臺技術框架—.NET Core已經日趨成熟,已經具備了支撐大型系統穩定運行的條件。本文將介紹明源云ERP平臺從.NET Framework向.NET Core遷移過程中的實踐經驗。
一、背景
? ??隨著ERP的產品線越來越多,業務關聯也日益復雜,應用間依賴關系也變得錯綜復雜,單體架構的弱點日趨明顯。19年初,平臺底層支持了分應用部署模式,將ERP從應用子系統層面進行了切割分離,邁出了從單體架構向微服務架構轉型的堅實一步。不久的將來,ERP會進一步將各業務拆分成眾多的微服務,而微服務勢必需要進行容器化部署和運行管理,這就要求ERP技術底層必須支持跨平臺,所以將現有ERP系統從.NET Framework遷移到 .NET Core平臺勢在必行。
二、遇到的問題和應對策略
? ? ERP在從Framework遷移到Core的時候主要要解決以下問題:
代碼文件和工程遷移。
Aspx文件遷移到Razor。
HttpModule和HttpHandler遷移。
ClownFish的Mvc機制遷移到Asp.Net Core MVC。
其他一些Windows平臺Api遷移到跨平臺。
發布和Docker部署。
? ? 以上每個主題中都包含了大量的技術細節,我們后面將陸續發文章分享經驗。本文先介紹關于項目工程遷移方面的內容,具體的遷移步驟如下:
dll引用實際是一個層級關系,從啟動項目往下找是可以找到一個最底層的依賴的,然后會存在一個依賴順序(拓撲排序),我們改造的時候也是從最底層開始改造起,逐個工程這樣遷移,遷移過程保證編譯通過。
在類庫遷移的時候核心有三個點,cs文件遷移,新的工程(.csproj)文件組織,dll引用組織。
在站點項目遷移的時候需要考慮靜態資源(js,css等)的組織。
在做完這些之后要考慮dll版本和最終打包發布。
三、遷移代碼文件
? ? .NET Framework 的 .csproj 文件極其龐大且難以理解,在新的.Net Core中推出了全新的的.csproj組織方式。新的工程文件主要有如下優勢:
在版本管理中更容易解決沖突:新方式包含了目錄下所有文件,老方式是需要顯示的引用(有點像黑名單和白名單的意思),這樣聲明的文件變得更少,從而減少了多人協作時XML合并沖突的風險。
可以指定多個開發框架,提供更好的兼容性:以往如果要同時兼容.Net3.5和.Net 4.5的話需要建兩個工程,通過文件鏈接來處理多個框架兼容的問題,新的組織方式一個工程文件即可處理。
引用更加簡潔:沒有對其他項目的基于GUID的引用,這可以提高文件的可讀性。同時基于NuGet的引用和路徑無關,意味著可以指定任意的NuGet包的位置。
嵌套的引用不需要重復指定(如果 A 引用了 B,B 引用了 C;那么 A 不需要顯式引用 C 也能調用到 C)。
? ? 項目遷移就是要實現對原來.cs代碼進行遷移,實現邏輯的復用,這里有三種遷移代碼文件的方式:
1、Copy文件: 將原有的文件復制復制到新文件夾重新組織(基本相當于重新寫一套就不贅述了)。
2、文件鏈接: 使用文件鏈接只需新建一個工程使用來組織代碼,基于Framework和Core可以分別再額外添加文件,下面是示例:
3、多框架:一個工程文件中有多個框架,下面是示例:
? ? 我們的策略是,根據不同的情況使用不同的遷移方式:
對于基礎平臺,由于是ERP的基礎底座,必須保證其遷移后的穩定和兼容,但基礎平臺的代碼量大,功能多,如果僅靠大量測試很難保證整體遷移的質量。由于Core和Framework的Api的一些差異,并不是完全兼容,但微軟還是提供了最大限度地功能兼容。為了以最低成本保障遷移質量,最終我們采用的是文件鏈接的遷移方式。
對于平臺的文檔服務和配置中心,功能較簡單,全面進行回歸測試的成本不大,所以我們采用了多框架的遷移方式。雖然.NET Core在HTTP框架方面并不兼容,我們需要重寫個別項目,這些項目的代碼量不大,所以對遷移質量的影響不大。
對于平臺的調度服務,我們采用重寫加上多框架的遷移方式。只是因為調度服務的核心引擎比較簡單,我們直接采用重寫的遷移方式,這部分后面將會有單獨的文章來介紹。
四、處理代碼文件兼容
? ? 當我們解決了工程層面的兼容之后,引入的文件編譯肯定會報錯,解決這個問題這個最核心的其實就是條件編譯了,示例如下:
? ? 雖然可以使用上述手段適配不兼容的API調用,但如果某個API被用到的地方特別多,就會出現大量重復的條件編譯,面對這個問題,我們可以將調用API這部分代碼抽離成單獨的Helper類。舉個例子:在Framework和Core中,從Http上下文中取參數的方法存在很大差異,而之前代碼中大量調用了這個API方法,我們可以將調用此API的代碼封裝到一個單獨的Helper類,如下代碼所示:
? ? 上述示例中有如下幾點比較重要:
命名空間中使用重命名的方式提供了參數的兼容使調用方代碼統一。
AsBase這類空方法提供了調用代碼的統一。
在方法級別使用了條件編譯,結合后續的處理邏輯兼容提供了調用方代碼統一。
在方法內部使用了條件編譯,直接提供了方法調用的兼容。
? ? 在命名空間重命名的技巧中還有另外一個用法也特別有用,還是舉例說明:
? ? 對比上述代碼可以發現,使用占位Attribute的方式代碼會簡潔很多,還有類似很多技巧這里就不一一說明。
? ? 改造過程中總結出以下實踐:
先用最簡單的條件編譯。
一個類里面方法和參數的特性導致重復的條件編譯比較多,考慮在命名空間部分使用重命名。
一個類里面方法內部重復的條件編譯比較多,考慮用類中私有方法來封裝這部分重復邏輯。
多個類里面方法內部重復的條件編譯比較多,考慮用用Helper類來封裝。
如果是方案級別的不一樣,考慮用一個接口在Framework和Core中不同的實現來處理。
五、處理包引用
? ??在處理完代碼層面兼容之后,還要處理第三方類庫的引用的問題。我們先通過下面兩張圖看看Framework和Core中引用的不同。
Framework引用關系:
Core引用關系:
? ? 在Framework中都是平鋪的,而在Core中引用是樹形結構;比如在Framework中A引用了B,B引用C,A如果要用到C的功能就必須要顯式的引用C,但是在CoreA是不需要引用C的。所以我們改造的時候遵循從底層網上改,如果底層引用的包上層就不再引用,這樣大大減少了項目中包引用的數量。新的引用機制也帶來了一些問題:
平臺周邊的類庫文件,如果按照原來方式是需要打包兩個dll,然后手動添加dll引用,這樣使倉庫體積變大,同時也不容易維護版本。
由于.Net Core的模塊化更細,一個包可能依賴于很多的其他包,這樣就導致了拉取nuget包很慢。
? ? 基于上述問題我們引入了Nexus作為我們的包管理工具。通過這個工具可以將自己的類庫推送到自己的NuGet倉庫管理,它同時還提供了代理的功能可以將遠程的包存儲到局域網,大大提高了拉包的速度。可能有些同學沒有使用過Nexus,這里做一個簡單的介紹:
功能: 提供的包類型非常豐富,支持nuget,maven,docker,npm,pypl,yum等,幾乎覆蓋市面所有流行的語言和工具。
Host倉庫: 支持自建倉庫可以上傳自己制作的包并共享出來。
Proxy倉庫: 支持為其他遠程倉庫地址代理,通過代理可以將其他網站的軟件包緩存到本地,大大提高拉包的效率。
Group倉庫: 支持分組將多個代理和私服打包成一個組,這樣遠程包的地址集中管理。
權限管理:在任意一個倉庫都可以控制增刪改查等權限。
總之:還有更多功能大家可以去試試(強烈推薦)。
六、處理靜態文件復用
? ??我們解決了類庫的遷移之后,由于在.NetCore改造過程中完全不涉及到前端js,css等文件的改造,所以要保證的js和css可以復用。在Framework中所有的資源文件都是相對于站點根目錄的路徑,而在Core中所有的資源文件都是在根目錄的wwwroot中,而在Core中提供了WebRootPath可以指定資源文件的路徑,我們在啟動過程中做了如下配置:
? ? .Net Core中可以根據環境變量來加載不同的配置文件,首先會默認加載appsettings.json,在開發環境中會額外的加載 appsettings.Development.json文件,后添加文件的配置項會覆蓋先添加文件的相同配置項,這樣在生產環境中使用默認的WebRootPath配置,而在開發環境中把WebRootPath指向原來Framework站點路徑,即可實現開發環境和生產環境的資源文件復用。
七、處理dll版本迭代
? ? 在ERP發布過程中是需要管理版本的,每個dll的版本都應該保持一致,那么就會涉及到如何通過修改一個地方讓所有dll版本都升級。
在Framework中我們用到了兩種方法:
Assembly文件鏈接,在周邊服務中Assembly中不需要有太多信息,這個時候通過一個只有版本信息的Assembly文件然后通過文件鏈接方式加入到各個工程中,發布時候只需修改一個Assembly的版本號即可。
老版本target文件引用,在每個工程中引入如下target文件,然后發布時候修改VersionAssembly中版本號即可。
在Core中我們采用引入props文件(和target文件類似) ,使用方式如下所示:
? ? 在Core中通過引入props文件這種方式可以將所有工程的通用描述包含進來,我們還用來在此文件中描述了dll文件簽名等其他內容。
八、程序打包發布
? ? 最后一步就是打包發布了, Framework中發布將編譯后的站點目錄進行打包,但是在Core中需要調用dotnet命令發布,發布之后還要考慮資源文件,dll版本,使用 dotnet publish {啟動項目相對路徑}?命令發布即可,在平臺服務中我們還使用了將獨立發布的模式。
? ? 因為ERP是前后端在一個倉庫,而且有眾多的資源文件,這里給出發布的腳本僅供大家參考:
九、總結
? ? 在改造過程中由于要兼容老的Framework的功能,給整個過程帶來了很多需要兼容的問題。初看之下可能會很亂,但是在一步步分析之后還是有思路可以做,并且在改造過程中大量采用了條件編譯延伸出來的技巧,使改造過程的思路和方法越來越清晰,最終完成了整個改造專項。
? ? 在整個過程中也遇到代碼不兼容的場景,這個時候就考慮從功能層面來兼容,比如:授權和權限,頁面路由,資源文件合并和替換等等,這些具體到功能細節改造的部分,將會在后面文章中陸續進行介紹,敬請期待。
------ END ------
作者簡介
熊同學:?研發工程師,目前負責ERP平臺相關的設計與開發工作。
也許您還想看
.NET Core MVC擴展實踐
研發協同平臺架構演進
明源云助手產品日志服務的演化歷程
ERP緩存實踐經驗分享
總結
以上是生活随笔為你收集整理的【复杂系统迁移 .NET Core平台系列】之迁移项目工程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: WeihanLi.Npoi 1.7.0
- 下一篇: 【复杂系统迁移 .NET Core平台系