我挑了一個先前寫的小工具,來試試看把它從原本的 .NET Framework 4.5 改成 .NET Core 2.0 平台會碰到那些問題。移轉過程順便引入第三方套件來改進程式碼。這裡也順便記一個好用的套件:Serilog。

簡介

挑選來移轉至 .NET Core 2 的專案是我先前已經放在 GitHub 的 Chinese-Converter。這是個命令列工具,可以將指定的檔案進行簡繁/繁簡中文的轉換。

原本我是以偷懶的作法,呼叫 Microsoft Word 來幫我做第一輪的簡繁轉換,然後再用我自己維護的簡繁對應辭庫進行第二輪的補強修正。既然 .NET Core 的重點在於跨平台,那麼自然就得去除對 MS Word API 的依賴。於是,除了修改 csproj 專案的內容,我還得修改一些程式碼。長話短說:我打算用(新?)同文堂的辭庫。
同文堂的簡繁對應辭庫,我在 GitHub 上面至少找到三個。於是我又在我的專案裡面增加一個工具:MergePhrase,用來合併從各方蒐集來的簡繁詞彙對照檔。目標是整合成單一檔案,作為 Chinese-Converter 的內建辭典,然後再以其他行業的術語辭庫作為額外補強。

有關 ChineseConverter 的部分說得夠多了。看一下跟 .NET Core 有關的部分吧。摘要如下:
  • 修改 .csproj 檔案
  • 使用 Serilog 來輸出 log
  • 部署

修改 .csproj 檔案

ChineseConverter 原本是針對 .NET Framework 4.5 來編譯的。現在要改成針對 .NET Core 2.0 平台。

我用 Visual Studio 2017 開啟專案的「屬性」,在「Target framework」下拉清單裡面只會出現 .NET Framework 各版本,而沒有 .NET Core 的選項。我的直覺反應就是去手動修改 .csproj 檔案。(也許有工具可以處理這件工作?)

註:這裡純粹是描述我對這個專案的做法,不見得適用所有類型的 .NET 專案。

首先,替換掉開頭的幾行文字(請看底下兩個程式碼區塊的註解說明):


然後把包含 <Compile Include> 項目的 <ItemGroup> 區塊整個刪除,例如:


此時用 Visual Studio 2017 開啟專案,看一下專案屬性裡面的 Target framework,竟然變成了 .NET Framework 4.0。

後來我把 .csproj 裡面的這行刪除:
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

然後用 Visual Studio 2017 開啟專案,Target framework 就變成 .NET Core 2.0 了。如下圖:


接著嘗試建置專案,出現一些編譯錯誤。根據錯誤訊息所提供的線索,我刪除了 AssemblyInfo.cs,然後開啟專案的「屬性」,切換至「Package」,並輸入套件的名稱、版本等資料:


到這個步驟做完,這個專案就可以建置成功了。
註:編譯之後所產生的應用程式檔案,副檔名不是 .exe,而是 .dll。

剩下的工作,就是把一些不相容於 .NET Core 2 的套件或程式碼改掉。在這當中,我移除了對 Microsoft.Office.Interop.Word.dll 的依賴,同時加入以下套件:

上述套件,Json.NET 和 Command Line Parser 的 .NET Core 版本在用法上跟以前沒有明顯差異,網路上可以找到很多教學文章。至於 Serilog 的部分,我嘗試把它跟 .NET 的 dependency injection API 接在一起用,所以這裡順便紀錄一下 Serilog 的用法。

使用 Serilog 來輸出 log

這裡會用到的套件/組件有:
  • Microsoft.Extensions.DependencyInjection 2.1.0-preview-final
  • Serilog 2.7.1-dev-00960
  • Serilog.Extensions.Logging 2.0.2
  • Serilog.Sinks.File 4.0.1-dev-00795

Step 0: 建立一個 .NET Core Console 應用程式專案


Step 1: 加入需要的套件

使用 NuGet Manager 或下列指令來安裝所需之套件:

Install-Package -IncludePrerelease Microsoft.Extensions.DependencyInjection
Install-Package -IncludePrerelease Serilog
Install-Package -IncludePrerelease Serilog.Extensions.Logging
Install-Package -IncludePrerelease Serilog.Sinks.File

完成後,專案的 .csproj 檔案裡面會加入以下內容:

Step 2: 修改 Program.cs

在 Main 函式中加入:


其中第二行程式碼的 ServiceCollection 是來自 Microsoft.Extensions.DependencyInjection。這些程式碼主要是參考自 Serilog 官方範例,用法挺簡單。

由於我只需要把 log 寫入至檔案,所以這裡使用了 .WriteTo.File(...)。Serilog 還支援多種輸出目標/格式,需要時可參閱官方文件。

一旦完成了 Serilog 的初始化設定,接著就可以直接透過 Log 類別來輸出 log 字串了。例如:


Log.Information("應用程式開始執行。");


Log 類別有個靜態屬性: Logger,其型別為 ILogger。由此可見,我們也可以把 Log.Logger 物件注入到其他類別。底下是「建構式注入」的例子:


var dict = new TSChineseDictionary(Log.Logger);


在 TSChineseDictionary.cs 裡面,建構函式需要接受一個 ILogger 參數,如下:

註:Serilog 的一個特色是能夠輸出「結構化 log 訊息」,這裡沒有用到。

部署

程式大致改好之後,我是透過 Solution Explorer 裡面對專案名稱點右鍵、選擇 Publish 的方式來產生部署所需的檔案。預設情況下,Visual Studio 會將此應用程式執行時所需要的檔案放在專案的  bin\Release\PublishOutput\ 目錄下。
註:如果開啟命令視窗,將現行目錄切換至專案的  bin\Debug\netcoreapp2.0\,然後用 dotnet myapp.dll 的方式來執行應用程式,可能會因為缺少其他相依組件而無法執行。
小結

由於我的這個 console app 專案只是個小工具而已,程式並不複雜,需要的第三方套件也都能找到支援 .NET Core 2 的版本,所以整個移轉過程算是蠻順利的。

文中沒有提到的是,同一個 solution 裡面還有一個單元測試專案。我同樣把它改成 target .NET Core 2.0,但採用了不同的方法:這次我是重新建立一個新的單元測試專案,再把檔案加進去。我覺得這樣反而簡單、乾脆。

完工以後,又上網搜了一下,發現也有類似的心得分享,而且更詳細。附在下方的〈延伸閱讀〉。

再補充一下 ChineseConverter 的進度:目前已經把網路上蒐集來的三個簡繁對應辭庫檔案合併好了。由於轉換的核心程式碼尚未改完,故仍放在工作分支,尚未合併至 master。此間,亦曾與同文堂的開發團隊成員接觸,詢問辭庫的問題。也許將來有機會再把字典檔的部分進一步完善吧。

Happy coding!

延伸閱讀