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

原文: 如何移植.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應用能夠跨平臺運行。html

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

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

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

首先重命名現有項目文件*.csproj爲*.Net46.csproj。而後使用VS2017新建一個新的基於.NET Core的項目,項目類型能夠是「類庫(.Net Core)」或者「類庫(.Net Standard)」。注意,VS2017會提示存在同名目錄,因此建立時能夠輸入一個不一樣的名稱,而後手工調整回來。web

 

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

經過VS2017 RC新建的項目,「類庫(.Net Core)」或者「類庫(.Net Standard)」,默認只有一個目標框架。咱們能夠編輯項目文件,使之支持面向多個目標框架。如支持目標框架爲.NET Standard 1.四、.Net Core App 1.0和.NET Framework 4.5,則這樣來修改。api

<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,使之支持多個目標框架。app

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

相關文章
相關標籤/搜索