1. 程式人生 > >揭示 NET Core和 NET Standard

揭示 NET Core和 NET Standard

                                                                                                   

作為.NET家族的最新成員,有很多關於.NET Core和.NET Standard的誤解,以及它們於.NET Framework之間的區別。在這篇文章,我會準確的解釋他們究竟是什麼,並看看何時應選擇哪一個。

在詳細介紹之前,首先檢視.NET的結構圖,它將幫助我們更好的理解.NET Core和.NET Standard所在的未知。當15年前,.NET 框架第一版釋出時, 它有一個單一的. NET 堆疊, 可用於構建 Windows 桌面和 Web 應用程式。從那時起,其他.NET 實現也開始出現,比如 Xamarin,使用Xamarin你可以為iOS和Android構建移動應用程式,以及macOS桌面應用程式,如圖 1所示.

圖 1 .NET 結構圖

關於.NET Core和.NET Standard如何融入.NET結構:

  • .NET Core: .NET Core是最新的一個.NET 實現。開放原始碼,可用於多個作業系統。使用.NET Core,你可以構建跨平臺控制檯應用程式和 ASP.NET Core Web 應用程式和雲服務。

  • .NET Standard: 這是所有的.NET實現所必須實現的基本Api (通常稱為base class library或 BCL)。通過以.NET Standard為目標,您可以構建能夠在所有. net 應用程式之間共享的庫, 無論它們執行在哪個.NET實現或在哪個作業系統上。

.NET Core 簡介

.NET Core是一個.NET Framework 和 Silverlight的一個分支,支援跨平臺並且完全開源。它通過啟用獨立的 XCOPY 部署來優化移動和伺服器工作負載。

為了更好的瞭解.NET Core,讓我們詳細檢視基於.NET Core的開發是如何進行的,同時探索新的基於命令列的工具。你也可以使用 Visual Studio 2017來進行. NET Core開發,但因為你正在閱讀本文,你很可能已經熟悉 Visual Studio,所以我將重點介紹新的體驗。

當.NET 建立時, 它為 Windows 上的快速應用程式開發進行了大量優化。在實踐中,這意味著,.NET 開發和 Visual Studio 是形影不離的好朋友。當然:使用 Visual Studio開發是一種衝擊。它極為高效,並且偵錯程式是我用過最好的工具。

但是, 在某些情況下, 使用 Visual Studio 並不是很方便。比如你只是想要簡單的通過.NET學習 C#,你不應該下載並安裝一個大型的IDE。或者你通過 SSH 訪問 Linux 機器,此時無法使用IDE。或者你只是更喜歡使用命令列介面 (CLI)。

這就是名為.NET Core CLI被建立的原因。.NET Core CLI 的主要命令為dotnet。你可以將其用於開發的幾乎所有方面, 包括建立、編譯、測試和打包專案。讓我們通過例項來了解它是如何操作的。

建立並執行一個 Hello World 控制檯應用程式 (我在Windows系統使用PowerShell,但是同樣可以在macOS或Linux的Bash中執行):

$ dotnet new console -o hello$ cd hello$ dotnet runHello World!

CLI中的 dotnet new 命令等於Visual Studio中的檔案|新建專案。 你可以建立各種不同的專案型別。輸入 dotnet new 以檢視預安裝的不同模板。

現在,讓我們將一些邏輯提取到一個類庫中。為此,需首先建立一個類庫專案平行於你的 hello 專案:

$ cd ..$ dotnet new library -o logic$ cd logic

你想要封裝的邏輯是構建一個 Hello World 的訊息,所以修改 Class1.cs 的內容為下面的程式碼:

namespace logic{    public static class HelloWorld    {        public static string GetMessage(string name) => $"Hello {name}!";`    }}

同時你還需要重新命名 Class1.cs 為 HelloWorld.cs:

$ mv Class1.cs HelloWorld.cs

注意,您不需要由於此變化更新專案檔案。使用在.NET Core的新專案檔案會包含專案目錄中的所有原始檔。因此,新增、 刪除和重新命名檔案並不需要再修改專案檔案。這使得命令列檔案操作更加順暢。

若要使用 HelloWorld 類,您需要更新 Hello 應用程式引用的邏輯類庫。你可以通過編輯專案檔案,或者通過使用dotnet add reference命令:

$ cd ../hello$ dotnet add reference ../logic/logic.csproj

現在,修改 Program.cs 檔案以使用 HelloWorld 類,如下所示.

using System;using logic;namespace hello    {        class Program        {            static void Main(string[] args)            {                Console.Write("What's your name: ");                var name = Console.ReadLine();                var message = HelloWorld.GetMessage(name);                Console.WriteLine(message);            }        }    }

要生成並執行您的應用程式,只需輸入 dotnet run

$ dotnet runWhat's your name: ImmoHello Immo!

你還可以從命令列建立測試。CLI 支援 MSTest,以及流行的 xUnit 框架。本示例中使用xUnit:

$ cd ..$ dotnet new xunit -o tests$ cd tests$ dotnet add reference ../logic/logic.csproj

改變 UnitTest1.cs 的內容,如下所示,新增一個測試。

using System;using Xunit;using logic;namespace tests{    public class UnitTest1    {        [Fact]        public void Test1()        {            var expectedMessage = "Hello Immo!";            var actualMessage = HelloWorld.GetMessage("Immo");            Assert.Equal(expectedMessage, actualMessage);        }    }}

現在你可以通過呼叫 dotnet test 執行測試:

$ dotnet testTotal tests: 1. Passed: 1. Failed: 0. Skipped: 0.Test Run Successful.

為了讓事情更有趣一點,讓我們建立一個簡單的 ASP.NET Core Web 站點:

$ cd ..$ dotnet new web -o web$ cd web$ dotnet add reference ../logic/logic.csproj

編輯 Startup.cs 檔案,修改app.Run方法,呼叫 HelloWorld類:

app.Run(async (context) =>{  var name = Environment.UserName;  var message = logic.HelloWorld.GetMessage(name);  await context.Response.WriteAsync(message);});

若要啟動 Web 開發伺服器,只需使用 dotnet run 命令:

$ dotnet runHosting environment: ProductionNow listening on: http://localhost:5000Application started. Press Ctrl+C to shut down.

瀏覽到所顯示的 URL,應該是 http://localhost:5000。

此時,你的專案資料夾結構應該看上去如下所示:

$ tree /f│├───hello│ hello.csproj│ Program.cs│├───logic│ HelloWorld.cs│ logic.csproj│├───tests│ tests.csproj│ UnitTest1.cs│└───webProgram.csStartup.csweb.csproj

為了便於使用Visual Studio編輯檔案的檔案,讓我們同樣建立一個解決方案檔案並向解決方案中新增的所有專案:

$ cd ..$ dotnet new sln -n HelloWorld$ ls -fi *.csproj -rec | % { dotnet sln add $_.FullName }   正如你所看到的,.NET Core CLI 功能強大,來自其他背景的開發人員會產生非常熟悉的感覺。無論你使用在Windows PowerShell中使用dotnet還是在Linux或macOS中使用,這些平臺的使用體驗頗為相似。   .NET Core的另一個巨大好處是它支援獨立部署。你可以使用Docker,它具有其自己的.NET Core執行時副本。這使你可以在同一臺機器使用不同版本的.NET Core而不互相干擾。因為.NET Core的開源特性,你還可以使用*nightly builds*甚至自己修改編譯,包含自己所做修改的版本。當然,這已超出了這篇文章的討論範圍。
.NET 標準簡介

當你構建現代應用程式時,您的應用程式往往跨平臺或需要使用多個.NET 實現。當今時代,客戶會期待他們可以在手機中使用 Web APP,資料通過基於雲端計算的後臺服務共享。當使用膝上型電腦時,他們也會想要通過 Web 站點獲取訪問許可權。對於自己的基礎架構,你可能想要使用命令列工具,甚至可能通過桌面應用程式讓您的員工管理系統。下面是不同.NET實現是如何實現這一目標的。

|           |  OS        |是否開源  |                   目的                              || .NET Framework | Windows     |   否   | 構建Windows應用程式,構建執行在IIS上的Web應用程式       || .NET Core    | Windows, Linux, macOS |  是  | 構建跨平臺命令列應用程式、ASP.NET Core應用程式、雲服務  || Xamarin     | iOS, Android, macOS  |   是 | 構建iOS、Android移動應用程式、macOS桌面應用程式        || .NET Standard     | N/A      |   是 | 建立可以被所有.NET實現(如.NET Core和.NET Framework)所引用的類庫    |

在這種環境中,程式碼共享成為一項重大挑戰。你需要理解 Api 是否可用,並確保共享的元件只使用在您正在使用的所有.NET 實現中可用的 Api。

這就是.NET Standard出現的原因,.NET Standard是一種規範,每個.NET Standard定義了所有.NET實現都必須提供的、符合該版本的Api集。你可以看作它然而另一個.NET 堆疊,只是你不能使用.NET Standard構建應用程式,而只能用來構建類庫。這是您要從任何地方引用的庫的. NET 實現。

你可能想知道.NET Standard包含了那些API,如果你熟悉.NET 框架,你應該熟悉我之前提到的BCL。BCL是獨立於UI框架和應用程式模型的基本 API集。它包括基型別、 檔案 I/O、 網路、 反射、 序列化、 XML 和其他。

所有的.NET堆疊都實現了某些版本的.NET Standard。按照經驗,當構建一個新的.NET實現時,它通常會實現最新版本的.NET Standard。

一個很好的比喻是 HTML 和瀏覽器: 想象HTML規範是.NET Standard,不同的瀏覽器則是各種.NET實現,例如.NET Framework,.NET Core和Xamarin。

在這一點上,你可能好奇如何來使用.NET Standard。事實上,你已經使用過了。還記得我們先前建立的邏輯類庫嗎?讓我們仔細看看專案檔案:

$ cd logic$ cat logic.csproj<Project Sdk="Microsoft.NET.Sdk">  <PropertyGroup>    <TargetFramework>netstandard2.0</TargetFramework>  </PropertyGroup></Project>

讓我們對比"Hello"控制檯應用程式的專案檔案:

$ cd ..\hello$ cat hello.csproj<Project Sdk="Microsoft.NET.Sdk">  <ItemGroup>    <ProjectReference Include="..\logic\logic.csproj" />  </ItemGroup>  <PropertyGroup>    <OutputType>Exe</OutputType>    <TargetFramework>netcoreapp2.0</TargetFramework>  </PropertyGroup></Project>

正如你所看到的,邏輯類庫有一個屬性為TargetFramework的專案,其值為 netstandard2.0,控制檯應用程式中該項的值為 netcoreapp2.0TargetFramework 屬性顯示了你使用了哪個.NET實現。所以,控制檯應用程式使用了.NET Core 2.0,而類庫則使用了.NET Standard 2.0。這意味著你可以在.NET Core程式,使用.NET Framework構建的程式,以及Xamarin程式中引用該邏輯類庫。

不幸的是,目前為止,大部分類庫還沒有針對.NET Standard編譯。它們中的絕大多數都是針對.NET Framework編譯的。當然,並不是所有的類庫都可以 (或應該) 都針對.NET Standard編譯。例如,包含 Windows Presentation Foundation (WPF) 控制元件的類庫,需要針對.NET Framework編譯,因為 UI 並不是.NET Standard的一部分。然而,更多的通用庫只針對.NET Framework編譯,僅僅是因為他們建立時,.NET Standard還不存在。

在.NET Standard 2.0 中,API 集增加到足夠大,因此大多數(如果不是全部)的通用庫都可以針對.NET Standard編譯。因此,Nuget上存在的通用類庫中,70%的類庫都只使用了.NET Standard 的 Api。但是,仍然只有一小部分被顯式標記為與.NET Standard相容。

為了使得開發人員可以無障礙的使用它們,添加了相容模式。如果你安裝的NuGet包沒有為你的目標框架提供類庫,也沒有為.NET Standard提供,NuGet會嘗試退回.NET Framework。換句話說,你可以同新增.NET Standard類庫一樣,新增.NET Framework的類庫引用。

我會為你展示此操作。在我的示例中,我將使用寫於2007年,名為PowerCollections的類庫,此類庫已經有一段時間未進行更新,並且仍然針對.NET Framework 2.0編譯。我將通過NuGet安裝這個類庫到 Hello 程式中。

$ dotnet add package Huitian.PowerCollections

此庫提供了BCL沒有提供一些集合型別,比如 bag,。讓我們修改 Hello 應用程式來使用它,如下所示.

using System;using Wintellect.PowerCollections;namespace hello{    class Program    {        static void Main(string[] args)        {            var data = new Bag<int>() { 1, 2, 3 };            foreach (var element in data)            Console.WriteLine(element);        }    }}

如果你執行該程式,您將看到以下內容:

$ dotnet runhello.csproj : warning NU1701: Package 'Huitian.PowerCollections 1.0.0' was restored using '.NETFramework,Version=v4.6.1' instead of the project target framework '.NETCoreApp,Version=v2.0'. This may cause compatibility problems.132

所以,剛剛發生了什麼?Hello應用程式的目標框架為.NET Core 2.0。由於.NET Core 2.0 實現.NET Standard 2.0,它同時具有對.NET Framework類庫引用的相容性模式。然而,並不是所有的.NET Framwork都能工作在所有的.NET實現中。例如,他們可能會使用 Windows Forms 或 WPF Api。NuGet則並不知道這些資訊,因此,它給了你一條警告訊息,似的你可以意識到這種情況,對由此造成的問題進行故障排除,減少排除故障的時間。

請注意,每次生成程式,你都將看到此警告。這避免了你在包安裝過程中沒有注意到警告,或者乾脆忘記了這個警告。

當然,沒有什麼比每次生成程式時收到警告更糟糕的了。所以,這裡的建議是,當你驗證你的應用程式後,就可以可以禁用針對該軟體包的警告。因為應用程式執行良好(它正確列印了您建立的bag中的內容),所以你現在可以禁止顯示此警告。要做到這一點,編輯 hello.csproj 檔案,並將 NoWarn 屬性新增到包引用:

<PackageReference Include="Huitian.PowerCollections" Version="1.0.0"   NoWarn="NU1701" />

如果你現在再次執行該程式,應該就不會再看到此警告了。如果你使用相容模式安裝另一個NuGet包,你同樣會收到針對另一個包的執行警告。

這款新工具還允許類庫在生成時,將NuGet程式包作為生成的一部分。這使得你與世界 (使用nuget.org) 或只是在您的組織內分享你的類庫 (通過釋出自己的包到Visual Studio Team Services 或 MyGet)成為了一項簡單的工作。新專案也支援多個目標框架,使得你在單個專案中針對多個.NET實現進行生成。這意味著您可以使用條件編譯 (#if) 以適配類庫到.NET 的特定實現。它還允許你為特定於平臺的 Api 構建.NET Standard wrappers。然而,這些都超出了本文的範圍。

  • 總結

.NET Standard規範了所有的.NET實現都必須提供的API。它為.NET家族帶來了一致性,並使你能夠生成可供所有.NET實現使用的類庫。它取代了PCL來構建共享的元件。

.NET Core是.NET Standard的其中一個實現,為建立控制檯應用程式、 Web 應用程式和使用ASP.NET Core的雲服務進行了優化。它的SDK中附帶了一個強大的工具,除使用Visual Studio進行開發外,還支援完整的基於命令列的開發流程。你可以瞭解通過aka.ms/netstandardfaq 和 aka.ms/netcore 瞭解更多.

Immo Landwerth is a program manager at Microsoft, working on .NET. He focuses on .NET Standard, the BCL and API design.

相關文章: 

原文地址:http://www.jianshu.com/p/ae24babe606d

.NET社群新聞,深度好文,微信中搜索dotNET跨平臺或掃描二維碼關注

640?wx_fmt=jpeg