我挑了一個先前寫的小工具,來試試看把它從原本的 .NET Framework 4.5 改成 .NET Core 2.0 平台會碰到那些問題。移轉過程順便引入第三方套件來改進程式碼。這裡也順便記一個好用的套件:Serilog。
簡介
挑選來移轉至 .NET Core 2 的專案是我先前已經放在 GitHub 的 Chinese-Converter。這是個命令列工具,可以將指定的檔案進行簡繁/繁簡中文的轉換。
原本我是以偷懶的作法,呼叫 Microsoft Word 來幫我做第一輪的簡繁轉換,然後再用我自己維護的簡繁對應辭庫進行第二輪的補強修正。既然 .NET Core 的重點在於跨平台,那麼自然就得去除對 MS Word API 的依賴。於是,除了修改 csproj 專案的內容,我還得修改一些程式碼。長話短說:我打算用(新?)同文堂的辭庫。
有關 ChineseConverter 的部分說得夠多了。看一下跟 .NET Core 有關的部分吧。摘要如下:
然後把包含 <Compile Include> 項目的 <ItemGroup> 區塊整個刪除,例如:
此時用 Visual Studio 2017 開啟專案,看一下專案屬性裡面的 Target framework,竟然變成了 .NET Framework 4.0。
後來我把 .csproj 裡面的這行刪除:
然後用 Visual Studio 2017 開啟專案,Target framework 就變成 .NET Core 2.0 了。如下圖:
接著嘗試建置專案,出現一些編譯錯誤。根據錯誤訊息所提供的線索,我刪除了 AssemblyInfo.cs,然後開啟專案的「屬性」,切換至「Package」,並輸入套件的名稱、版本等資料:
到這個步驟做完,這個專案就可以建置成功了。
剩下的工作,就是把一些不相容於 .NET Core 2 的套件或程式碼改掉。在這當中,我移除了對 Microsoft.Office.Interop.Word.dll 的依賴,同時加入以下套件:
上述套件,Json.NET 和 Command Line Parser 的 .NET Core 版本在用法上跟以前沒有明顯差異,網路上可以找到很多教學文章。至於 Serilog 的部分,我嘗試把它跟 .NET 的 dependency injection API 接在一起用,所以這裡順便紀錄一下 Serilog 的用法。
使用 Serilog 來輸出 log
這裡會用到的套件/組件有:
Step 0: 建立一個 .NET Core Console 應用程式專案
Step 1: 加入需要的套件
使用 NuGet Manager 或下列指令來安裝所需之套件:
完成後,專案的 .csproj 檔案裡面會加入以下內容:
Step 2: 修改 Program.cs
在 Main 函式中加入:
其中第二行程式碼的 ServiceCollection 是來自 Microsoft.Extensions.DependencyInjection。這些程式碼主要是參考自 Serilog 官方範例,用法挺簡單。
由於我只需要把 log 寫入至檔案,所以這裡使用了 .WriteTo.File(...)。Serilog 還支援多種輸出目標/格式,需要時可參閱官方文件。
一旦完成了 Serilog 的初始化設定,接著就可以直接透過 Log 類別來輸出 log 字串了。例如:
Log 類別有個靜態屬性: Logger,其型別為 ILogger。由此可見,我們也可以把 Log.Logger 物件注入到其他類別。底下是「建構式注入」的例子:
在 TSChineseDictionary.cs 裡面,建構函式需要接受一個 ILogger 參數,如下:
註:Serilog 的一個特色是能夠輸出「結構化 log 訊息」,這裡沒有用到。
部署
程式大致改好之後,我是透過 Solution Explorer 裡面對專案名稱點右鍵、選擇 Publish 的方式來產生部署所需的檔案。預設情況下,Visual Studio 會將此應用程式執行時所需要的檔案放在專案的 bin\Release\PublishOutput\ 目錄下。
由於我的這個 console app 專案只是個小工具而已,程式並不複雜,需要的第三方套件也都能找到支援 .NET Core 2 的版本,所以整個移轉過程算是蠻順利的。
文中沒有提到的是,同一個 solution 裡面還有一個單元測試專案。我同樣把它改成 target .NET Core 2.0,但採用了不同的方法:這次我是重新建立一個新的單元測試專案,再把檔案加進去。我覺得這樣反而簡單、乾脆。
完工以後,又上網搜了一下,發現也有類似的心得分享,而且更詳細。附在下方的〈延伸閱讀〉。
再補充一下 ChineseConverter 的進度:目前已經把網路上蒐集來的三個簡繁對應辭庫檔案合併好了。由於轉換的核心程式碼尚未改完,故仍放在工作分支,尚未合併至 master。此間,亦曾與同文堂的開發團隊成員接觸,詢問辭庫的問題。也許將來有機會再把字典檔的部分進一步完善吧。
Happy coding!
延伸閱讀
簡介
挑選來移轉至 .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 專案。
首先,替換掉開頭的幾行文字(請看底下兩個程式碼區塊的註解說明):
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- 底下是準備要被替換的文字 --> | |
<?xml version="1.0" encoding="utf-8"?> | |
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> | |
<PropertyGroup> | |
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> | |
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> | |
<ProjectGuid>{B395A62E-B988-4370-AB66-D76A4FC49C9E}</ProjectGuid> | |
<OutputType>Exe</OutputType> | |
<AppDesignerFolder>Properties</AppDesignerFolder> | |
<RootNamespace>ChineseConverter</RootNamespace> | |
<AssemblyName>tscc</AssemblyName> | |
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion> | |
<FileAlignment>512</FileAlignment> | |
</PropertyGroup> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- 把前面的內容替換成底下文字 --> | |
<Project Sdk="Microsoft.NET.Sdk"> | |
<PropertyGroup> | |
<OutputType>Exe</OutputType> | |
<RootNamespace>ChineseConverter</RootNamespace> | |
<AssemblyName>tscc</AssemblyName> | |
<TargetFramework>netcoreapp2.0</TargetFramework> | |
</PropertyGroup> |
然後把包含 <Compile Include> 項目的 <ItemGroup> 區塊整個刪除,例如:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<ItemGroup> | |
<Compile Include="TSChineseDictionary.cs" /> | |
<Compile Include="Program.cs" /> | |
<Compile Include="Properties\AssemblyInfo.cs" /> | |
<Compile Include="TSChineseConverter.cs" /> | |
</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 檔案裡面會加入以下內容:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.1.0-preview1-final" /> | |
<PackageReference Include="Serilog" Version="2.7.1-dev-00960" /> | |
<PackageReference Include="Serilog.Extensions.Logging" Version="2.0.2" /> | |
<PackageReference Include="Serilog.Sinks.File" Version="4.0.1-dev-00795" /> |
在 Main 函式中加入:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 設定 DI | |
var serviceProvider = new ServiceCollection() | |
.AddLogging(loggingBuilder => loggingBuilder.AddSerilog(dispose: true)) | |
.BuildServiceProvider(); | |
// 建立 logger | |
Log.Logger = new LoggerConfiguration() | |
.Enrich.FromLogContext() | |
.WriteTo.File(opts.LogFileName, Serilog.Events.LogEventLevel.Information) | |
.CreateLogger(); |
其中第二行程式碼的 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 參數,如下:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class TSChineseDictionary | |
{ | |
private ILogger _logger; | |
public TSChineseDictionary(ILogger logger) | |
{ | |
_logger = logger; | |
} | |
} |
部署
程式大致改好之後,我是透過 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!
延伸閱讀
沒有留言: