如何移植.NET Framework項目至.NET Core?


公司的項目一直采用.NET框架來開發Web項目。目前基礎類庫均為.NET Framework 4.6.2版本。Caching, Logging,DependencyInjection,Configuration等基礎設施相關的依賴庫一直和官方保持同步,目前是1.1版本。.NET Core越來越趨於穩定,新的開發工具也在三月份發布。因此,計划將.NET Framework移植至.NET Core/Strandard。目的是使基於.NET開發的Web應用可以跨平台運行。

按應用場景將公司的項目分為基礎類庫,基礎服務和應用項目。基礎類庫以包的形式提供各類基礎功能。基礎服務通過Wcf項目搭建或者通過Web API項目搭建。應用項目則是Web Mvc項目為主。基礎類庫和基礎服務是以一個一個解決方案的形式存在。每個解決方案的結構,包含一個或者多個類庫項目,一個或多個控制台項目,它們分別用於功能實現、單元測試、功能演示。如果全部要移植,那么優先級應該是基礎類庫 -> 基礎服務 -> 應用項目。此次移植的對象是基礎類庫。

基礎類庫最終會以包的形式通過NuGet發布出去,目前只面向.NET Framework框架。移植的目標之一,是讓包也能被面向.NET Core、.NET Standard框架的項目引用。結合官方資料,我選擇了直接遷移的方案。即直接將項目文件轉換為新的基於.NET Core的項目文件。下面詳細說明移植的細節。

1. 新建基於.NET Core的項目。

首先重命名現有項目文件*.csproj為*.Net46.csproj。然后使用VS2017新建一個新的基於.NET Core的項目,項目類型可以是“類庫(.Net Core)”或者“類庫(.Net Standard)”。注意,VS2017會提示存在同名目錄,所以創建時可以輸入一個不同的名稱,然后手工調整回來。

 

2. 編輯項目文件,使之支持面向多個目標框架。

通過VS2017 RC新建的項目,“類庫(.Net Core)”或者“類庫(.Net Standard)”,默認只有一個目標框架。我們可以編輯項目文件,使之支持面向多個目標框架。如支持目標框架為.NET Standard 1.4、.Net Core App 1.0和.NET Framework 4.5,則這樣來修改。

<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
      <TargetFrameworks>netstandard1.4;netcoreapp1.0;net45</TargetFrameworks>
    </PropertyGroup>
</Project>

注意,官方文檔中提供了.NET支持的目標框架列表,你可以查詢更多其他的目標框架。如果要兼容較低版本的框架,則目標框架版本不宜設置過高。如“net45”可用於.NET Framework 4.5 ~ 4.6.2等版本。如“net46”則只能用於.NET Framework 4.6 ~ 4.6.2等版本。

3. 修改應用程序代碼相關API,使之支持多個目標框架。

a. 因目標框架提供的API不相同。故必要時可添加條件編譯符號以便支持不同的運行時版本。

以下是常見的條件編譯符號列表。

.NET Framework 2.0 --> NET20
.NET Framework 3.5 --> NET35
.NET Framework 4.0 --> NET40
.NET Framework 4.5 --> NET45
.NET Framework 4.5.1 --> NET451
.NET Framework 4.5.2 --> NET452
.NET Framework 4.6 --> NET46
.NET Framework 4.6.1 --> NET461
.NET Framework 4.6.2 --> NET462
.NET Standard 1.0 --> NETSTANDARD1_0
.NET Standard 1.1 --> NETSTANDARD1_1
.NET Standard 1.2 --> NETSTANDARD1_2
.NET Standard 1.3 --> NETSTANDARD1_3
.NET Standard 1.4 --> NETSTANDARD1_4
.NET Standard 1.5 --> NETSTANDARD1_5
.NET Standard 1.6 --> NETSTANDARD1_6

 關於條件編譯符號的應用,如以下代碼:

using System;
using System.IO;
namespace Baza.NetStandardTester
{
    public class PathHelper
    {
        public string BaseDirectory { get; set; }
        public PathHelper()
        {
#if NET45
            BaseDirectory = AppDomain.CurrentDomain.BaseDirectory;
#endif
        }
        public string GetRootedPath(string path)
        {
            string rootedPath = path ?? string.Empty;
            if (!Path.IsPathRooted(rootedPath))
            {
                if (string.IsNullOrEmpty(BaseDirectory))
                    throw new ArgumentNullException("請先設置BaseDirectory屬性");
                rootedPath = Path.Combine(BaseDirectory, rootedPath);
            }
            string directory = Path.GetDirectoryName(rootedPath);
            if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
            {
                Directory.CreateDirectory(directory);
            }
            return rootedPath;
        }
    }
}

代碼說明,PathHelper提供GetRootedPath方法用於根據相對路徑計算出絕對路徑。當運行時為.NET Core時,BaseDirectory屬性需要手動設置。當運行時為.NET Framework 4.5時,由構造器對BaseDirectory屬性進行賦值。注意System.AppDomain.CurrentDomain.BaseDirectory用於獲取托管程序執行路徑,類AppDomain只存在於.NET Framework中。

b. .NET Standard是個基於包的框架。當你需要某個API時,如IDataReader,你需要安裝System.Data.Common包。如果是使用.NET Framework,則在命名空間System.Data下可以找到IDataReader而無需按照包。借助https://packagesearch.azurewebsites.net/工具,你可以快速定位某個API在哪個包中。

c. 基於.NET Core的項目,包版本號和其他元數據,都存儲在*.csproj中,不會使用AssemblyInfo.cs文件,即移植時,這個文件可以刪除。但是.NET Framework項目還是會繼續使用該文件。

4. 同一解決方案,類庫間的引用策略。

在引用類庫時,要注意目標框架的兼容問題。如,“類庫(.Net Standard)”項目,能夠被.NET Core App、.NET Framework和其他.NET Standard項目引用。這個是因為.NET Core App和.NET Framework都支持相應版本的.NET標准庫。下表顯示了支持 .NET 標准庫的整套 .NET 運行時。

平台名稱 Alias                
.NET Standard netstandard 1.0 1.1 1.2 1.3 1.4 1.5 1.6 2.0
.NET 核心 netcoreapp 1.0 vNext
.NET Framework net 4.5 4.5.1 4.6 4.6.1 4.6.2 vNext 4.6.1
Mono/Xamarin 平台   vNext
通用 Windows 平台 uap 10.0 vNext
Windows win 8.0 8.1          
Windows Phone wpa 8.1          
Windows Phone Silverlight wp 8.0              

注意,如果項目是面向多目標框架的,那么引用類庫時,被引用類庫也要支持面向多目標框架。

5. 單元測試

如果是使用.NET Framework類庫項目來存放單元測試代碼,那么可能會遇到一點問題。在VS2017 RC中,測試資源管理器無法識別出這些測試單元。通過新建“單元測試項目(.NET Framework)”,將生成的同名*.csproj覆蓋原來的項目文件,測試管理器即可識別出來。

5. MSBuild自動編譯新的解決方案

Windows下,按Release配置對整個解決方案編譯。

"c:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\MSBuild.exe" XXX.sln /p:Configuration=Release;Platform="Any CPU"

會在相關類庫根目錄下\bin\Release目錄中,生成net46和netstandard1.6兩個目錄。

6. 使用dotnet-nuget-push發布包

使用vs2017打包時,只需右擊要打包的項目,選擇“打包”,即可在.\bin\Debug或.\bin\Release下生成XXX.0[.0].0.nupkg文件,然后將這個文件.nupkg上傳至nuget.org中。通過調用dotnet-nuget-push可以自動化這個發布過程,因此這種方式會更加方便。

dotnet nuget push XXX.0[.0].0.nupkg -k 4003d786-0000-4004-bfdf-c4f3e8ef9b3a -s http://customsource/

k:服務器的 API 密鑰 s:服務器 URL,如發布到nuget.org,則可以這樣寫。

dotnet nuget push XXX.0[.0].0.nupkg -k 4003d786-0000-4004-bfdf-c4f3e8ef9b3a -s https://www.nuget.org/api/v2/package

通常在windows下,會將dotnet-nuget-push寫在批處理文件中來完成基本類庫的部署工作。

總結

通過此方案遷移后,最終保留新的解決方案和項目文件,舊的解決方案和項目文件在移植的過程中被刪除。之后將按照新的解決方案來跨平台開發。基本類庫的移植工作就介紹到這里。源代碼的移植將是個挑戰。譬如部分源碼所引用的API在.NET Core框架下不存在時如何處理?另外,基礎服務和Web Mvc項目的移植,因為要部署到linux中。也將會遇到各種問題。

參考資源

1. 組織項目以支持 .NET Framework 和 .NET Core

2. dotnet-nuget-push

3. packagesearch.azurewebsites.net

4. .NET 標准庫

5. Developing Libraries with Cross Platform Tools

6. Target Frameworks

7. Porting to .NET Core from .NET Framework


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM