隨著Microsoft擁抱開源的口號,.NET Framework也正式登上了其他平台,其中包含了Linux與OSX,與以往的3rd Party Mono不同,新的.NET Core具備官方的支援及完整的Roadmap。
為了登上其他舞台,.NET Core可以說從根源開始重新打造,在早期版本中Linux、OSX上仍是使用Mono Runtime,隨著時間的推移,現在的1.1 RTM中Mono的身影已經完全消失了,取而代之的是Native Platform Runtime,這代表著.NET平台新時代的來臨,也意味著Microsoft正走在一個Java曾走過的道路,Cross Platform、Write once,Run Anywhere。
第一個程式
在開始寫程式前,你得先安裝.NET Core,這不難,照著網頁上寫的步驟做就可以了。
https://www.microsoft.com/net/core#windowsvs2015
本文使用Visual Studio 2015做為開發工具,當然,你也可以使用跨平台、更簡便的Visual Studio Code,同樣可以達到目的。
準備好開發工具後,就可以透過Visual Studio 2015來建立第一個.NET Core應用程式,這裡使用Console Application,因為命令列式的應用程式可以讓我們以最快速、最簡單的步驟直達核心。
按下OK後就會看到熟悉的C#程式碼,編譯後能夠立刻執行。
如圖所示,你會發現這與傳統的.NET Console Application有兩個地方不同,第一個是.NET Core透過dotnet.exe來執行程式,如下圖所示。
第二個是編譯後的是一個DLL檔案,而不是傳統的EXE檔。
這其實有個目的,叫做Binary Sharing,也就是說你可以把這個DLL放到各種平台上執行而不需重新編譯,跟以往Java宣稱的Write Once、Run Anywhere是同樣道理。
在.NET Core中,除了編譯後的DLL檔之外,還有幾個很重要的JSON檔案:,.runtimeconfig.json這個檔案中描述了這個DLL是使用哪一種Runtime Framework,.NET Core可以使用不同的Runtime Framework,例如.NET 4.5.2、4.6、.NET Core 1.0、.NET Core 1.1等等,deps.json則描述了這個應用程式需要的Librarys,例如EntityFramework等等,這個檔案通常用於當只分發主程式而沒有分發其他Librarys,例如只複製DLL跟runtime.json到目的地,然後使用dotnet restore來下載其他相依的Librarys,這兩個json檔案的源頭是project.json。
{
"version": "1.0.0-*",
"buildOptions": {
"emitEntryPoint": true
},
"dependencies": {
"Microsoft.NETCore.App": {
"type": "platform",
"version": "1.1.0"
}
},
"frameworks": {
"netcoreapp1.0": {
"imports": "dnxcore50"
}
}
}
注意,runtime.json檔案必須存在,否則這個應用程式無法執行。
Binary Sharing?
談到跨平台,Binary Sharing就是一個很重要的議題,通常我們希望編譯後的結果可以拿到不同的平台上執行,而不是需要在不同平台上在編譯過後才能執行,.NET Core的應用程式具備了Binary Sharing特點,這裡我們用Cent OS為例(你必須事先在上面安裝好.NET Core)。
https://www.microsoft.com/net/core#linuxcentos
透過SSH或是FTP將編譯好的DLL及json檔案複製到Cent OS機器上,如你所見,同樣的指令,同一個DLL,不須重新編譯就可以執行,這就是Binary Sharing。
目前Visual Studio 2015的Template會指定.NET Core 1.0.1版本,所以如果Linux上的是最新的1.1.0版本,你會看到以下的訊息。 解法很簡單,就是在project.json中指定1.1.0即可。
project.json
|
自然,Binary Sharing同樣適用於Class Library。
Multi Framework Support
.NET Core可以支援多個Framework,這意思是你可以用.NET Core方式來撰寫應用程式,然後在Windows上用.Net Framework 4.5作為Runtime來執行,而不需安裝.NET Core,這可以透過修改project.json來完成。
{
"version": "1.0.0-*",
"buildOptions": {
"emitEntryPoint": true
},
"dependencies": {},
"frameworks": {
"netcoreapp1.0": {
"imports": "dnxcore50",
"dependencies": {
"Microsoft.NETCore.App": {
"type": "platform",
"version": "1.1.0"
}
}
},
"net452": {}
}
}
修改完後重新編譯,會發現輸出多了一組net452目錄。
在裡面可以看到熟悉的EXE檔。
這時內建的條件式編譯可以協助你針對不同Runtime調整行為,例如在完整的.NET Framework中使用Registry來儲存設定,在.NET Core使用本地的json檔之類的。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace SimpleConsoleApp1
{
public class Program
{
public static void Main(string[] args)
{
#if NET452
Console.WriteLine("Hello .NET Framework");
#else
Console.WriteLine("Hello .NET Core");
#endif
Console.ReadLine();
}
}
}
以下是使用.NET Framework的情況。
接著是.Net Core的情況。
很有趣是吧?
Self-Contained
除了使用Binary Sharing技術來分發應用程式之外,你也可以透過dotnet publish指令來打包Self-Contained應用程式,這意思是應用程式將內含.NET Core及相依的Librarys,目的平台不需要事先安裝.NET Core,簡單的說在Linux上,使用者看到的是執行檔而不是DLL,要完成這個,必須修改project.json檔案。
{
"version": "1.0.0-*",
"buildOptions": {
"emitEntryPoint": true
},
"dependencies": {},
"frameworks": {
"net452": {},
"netcoreapp1.0": {
"imports": "dnxcore50",
"dependencies": {
"Microsoft.NETCore.App": {
"version": "1.1.0"
}
}
}
},
"runtimes": {
"win7-x64": {},
"centos.7-x64": {}
}
}
要特別注意的是我們移除了netcoreapp1.0中的platform區段,否則無法編譯出self-contained的檔案,最後下達以下命令即可產生CentOS上的版本。
dotnet publish -c release -r centos.7-x64
最後把整個publish目錄的內容複製到CentOS上就可以執行(注意,你必須透過chmod來調整SimpleConsoleApp檔案為可執行檔案)。
Writing on Windows、Running on Linux、Debug on Windows
當應用程式需要執行在Windows以外的平台時,使用Docker來除錯是最簡單的的方式,但有時真實環境並非是Docker,而你又需要針對真實環境除錯時,這時就需要費點功夫了。首先必須要修改project.json,讓編譯器產生portable的pdb資訊。
{
"version": "1.0.0-*",
"buildOptions": {
"emitEntryPoint": true,
"debugType": "portable"
},
"dependencies": {},
"frameworks": {
"netcoreapp1.0": {
"imports": "dnxcore50",
"dependencies": {
"Microsoft.NETCore.App": {
"version": "1.1.0"
}
}
}
},
"runtimes": {
"win7-x64": {},
"centos.7-x64": {}
}
}
接著設定專案的輸出目錄為共用。
通常設定存取等級為everyone是最簡便的方式,然後到目標機器上安裝clsdbg套件。
curl -sSL https://raw.githubusercontent.com/Microsoft/MIEngine/getclrdbg-release/scripts/GetClrDbg.sh | bash /dev/stdin vs2015u2 ~/clrdbg
完成後home的目錄結構會變成類似下面這樣。
接著要在目標機器上mount shared folder。
最後需要一個.xml檔案,用來描述Windows如何透過SSH連結到目標LINUX機器。
Lanuchdebug.xml
<?xml version="1.0" encoding="utf-8" ?>
<PipeLaunchOptions xmlns="http://schemas.microsoft.com/vstudio/MDDDebuggerOptions/2014"
PipePath="d:\develop\putty\plink.exe" PipeArguments="192.168.1.94 -l <user> -pw <password> -batch -t ~/clrdbg/clrdbg --interpreter=mi"
TargetArchitecture="x64" MIMode="clrdbg" ExePath="dotnet" WorkingDirectory="~/myapp" ExeArguments="SimpleConsoleApp1.dll">
</PipeLaunchOptions>
完成準備後,就可以在Visual Studio 2015的Command Window中下達以下指令進入Debug模式。
Debug.MIDebugLaunch /Executable:dotnet /OptionsFile:d:\temp1\lanuchdebug.xml
順利的話可以停在設立的中斷點。
下次有機會我們再來聊聊.NET Core Hosting,這也很有趣。