本文為翻譯文章,原文:Packages, Metapackages and Frameworks
.NET Core是一個由NuGet包組成的平台。一些產品受益於細粒度包的定義,也有一些受益於粗粒度包的定義。為了適應這種二重性,.NET Core平台被分為一組細粒度的包(package)以及一些被稱為元包(metapackage)的較粗粒度的包。
每一個.NET Core包支持多個.NET運行時,它們代表着不同的框架。這些框架既包括傳統的.NET Framework(如net4.6),也包含基於包的新框架,這些新框架建立了定義框架的新模型。這些基於包的框架完全由包定義而成,包與框架之間形成較強的關聯關系。
包
.NET Core由一組包構成,這些包提供了基元類型、高級數據類型、應用程序組成類型和一些常見的實用工具。每一個包表示一個和包同名的程序集,如, System.Runtime包中含有System.Runtime.dll程序集。
定義細粒度的包有如下好處:
-
細粒度的包在開發、測試過程中與其它包的關聯有限
-
細粒度的包可以提供對不同操作系統和CPU的支持
-
細粒度的包可以只依賴某個特定的庫
-
在發布應用時,未被引用的包不會成為應用的一部分,因此應用程序會有更小的體積
有些細粒度包的優點只會在特定場景中表現出來。如,通常.NET Core 的所有包會在同一計划內提供對同一平台的支持。這種情況下,補丁會以小的單個更新包的形式發布和安裝。由於這種小范圍的變化,驗證補丁是否可用所花費的時間,可以限制到對單個庫的需求中。
下面列出了.NET Core平台上的一些關鍵NuGet包:
-
System.Runtime - 這是最基本的.NET Core包,包括Object, String, Array, Action 和IList<T>.
-
System.Collections - 表示一組常用泛型集合,包括List<T> 和Dictionary<K,V>.
-
System.Net.Http - 用於HTTP通訊的類型,包括HttpClient 和HttpResponseMessage.
-
System.IO.FileSystem -用於讀寫基於磁盤的本地或網絡存儲類型,包括File和Directory.
-
System.Linq - 用於查詢對象,包括including Enumerable 和ILookup<TKey, TElement>.
-
System.Reflection - 用於加載、檢查、創建類型,包括Assembly, TypeInfo 和MethodInfo.
通常,與逐個添加項目所需要的包相比,使用元包的方式來添加項目依賴更加容易,因為元包是一組常用包的集合。當你需要某個單獨的包時,你可以使用下面例子中添加對System.Runtime
引用的方式來添加對它的引用。
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>netstandard1.6</TargetFramework> </PropertyGroup> <ItemGroup> <PackageReference Include="System.Runtime" Version="4.3.0" /> </ItemGroup> </Project>
元包
元包是一個NuGet包約定,用於描述一組放在一起有意義的包。 這些包是通過依賴項來被描述的。可以通過為這組包指定一個框架來建立一個框架(這話拗口,原文:They can optionally establish a framework for this set of packages by specifying a framework.)。
以前版本的.NET Core工具(project.json和基於csproj的工具)在默認情況下會指定一個框架和元包 。不過,現在,元包被目標框架隱式引用,這樣一來每個元包都和目標框架關聯在一起。例如,netstandard1.6
框架引用了NetStandard.Library 1.6.0
元包。類似的,netcoreapp1.1
框架引用了Microsoft.NETCore.App 1,1.0
元包。更過信息,參考.NET Core SDK中元包的隱式引用。
指定一個框架會隱式實現對元包引用,同時也會添加對元包依賴項的引用。這樣,元包中的所有類庫都能夠被IDE智能感知,也可以被打包到你的應用中。
使用元包有以下好處:
-
在引用大量細粒度包時有更好的用戶體驗
-
定義了一組經過測試且運行良好的包(包括指定的各種版本)
.NET 標准庫元包(.NET Standard Library metapackage):
- NETStandard.Library - 表示.NET標准類庫的一部分。所有的.NET 實現(如,.NET Framework、.NET Core 和 Mono)都支持.NET 標准類庫。
NETStandard.Library
用於建立netstandard
框架。
.NET Core核心元包有:
-
Microsoft.NETCore.App - .NET Core發行版本類庫的一部分,用於建立 .NETCoreApp框架,它依賴
NETStandard.Library
。 -
Microsoft.NETCore.Portable.Compatibility - 一組基於mscorlib的運行於.NET Core上的可移植類庫
框架
每個.NET Core包都支持多個運行時框架。這些框架描述一組可用於你所指定的框架的API(和一些其它特征)。當加入新的API時,這些框架的版本號也會發生相應的變化。
例如, System.IO.FileSystem 支持以下框架:
- .NETFramework,Version=4.6
- .NETStandard,Version=1.3
- 6 Xamarin platforms (如, xamarinios10)
這些運行時框架使用不同的方式進行框架的定義,對比學習前兩個框架會大有裨益。
.NETFramework,Version=4.6
框架表示可用於.NET Framework 4.6之上的API。
我們可以編寫基於.NET Framework 4.6
引用程序集的庫,並以NuGet 包的方式在 net46 lib 文件夾中發布這些庫。這些庫可用於那些基於或兼容.NET Framework 4.6
的應用。這是所有框架的傳統工作方式。
.NETStandard,Version=1.3
是一個基於包的框架。它依靠包來定義目標框架以及公開該框架的API。
基於包的框架
包與框架之間是雙向關系。首先為一個給定框架定義可用的API,如netstandard1.3
。用於netstandard1.3
框架(或兼容框架,如netstandard1.0
)的軟件包定義該框架上可用的API。這看起來像是循環定義,但不是。基於包的框架上的API由包來定義,框架本身並不定義任何API。
其次,是這種雙向關系中的第二部分,資產選擇(asset selection)。包可以包含用於多框架的資產。對於一組包或者元包的引用,框架需要決定選擇哪種資產,如net46
或netstandard1.3
。選擇正確的資產是很重要的。如,一個net46
資產可能不兼容.NET Framework 4.0
或 .NET Core 1.0
。

上圖描述了這種雙向關系。API指定並定義框架。框架選擇資產。資產提供具體的API實現。
.NET Core
平台上使用的兩個主要的基於包的框架是:
-
netstandard
-
netcoreapp
.NET 標准
.NET標准(目標框架名:netstandard)框架是指基於.NET標准庫(.NET Standard Library)而定義和創建的API。這些庫計划支持以.NET 標准框架為目標框架的多個運行時。它們支持任何與.NET標准(.NET Standard )兼容的運行時,如.NET Core、.NET Framework和Mono/Xamarin(下面附上一張圖作為補充)。每個運行時都支持一組.NET Standard版本,具體取決於它們所要實現的API。

標准框架隱式引用NETStandard.Library
元包。如,下面的MSBuild項目文件顯示了當前項目的目標框架是netstandard1.6
,這個框架引用.NET Standard Library version 1.6
元包。
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>netstandard1.6</TargetFramework> </PropertyGroup> </Project>
但是,框架和項目文件中所引用的元包無需一一對應,你可以在項目文件中使用<NetStandardImplicitPackageVersion>
來制定一個版本號低於元包版本號的框架。如,下面的配置框文件是有效的。
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>netstandard1.3</TargetFramework> </PropertyGroup> <ItemGroup> <NetStandardImplicitPackageVersion Include="NetStandardLibrary" Version="1.6.0" /> </ItemGroup> </Project>
netstandard1.3
框架使用NETStandard.Library 1.6.0
可能看起來比較奇怪。但這種使用情況是合法的,因為元包向后兼容低版本的netstandard
。若你已經將1.6.0版本的元包並將其應用到自己的面向多個netstandard
版本的庫中。通過這種向后兼容的方式,你只需還原(restore)NETStandard.Library1.6.0
而無需關注更早的版本。
與此相反,netstandard1.6
引用NETStandard.Library 1.3.0
是不被允許的,因為低版本的元包不會公開任何構建高版本框架的資產。元包資產的版本控制使得元包和它們所描述的框架的最高版本相匹配。借助版本控制,NETStandard.Library
的第一個版本是1.6.0,它包含netstandard1.6
的資產。上述例子中的1.3.0版本只是為了舉例需要,事實上它並不存在。
.NET Core 應用
.NET Core 應用(目標框架:netcoreapp)框架表示.NET Core 發行版和它提供的控制台應用程序模型附帶的包和相關API。.NET Core應用必須使用該框架,因為它基於的控制台應用模型的庫僅僅運行於.NET Core框架上。使用這個框架可以限制應用和庫只運行於.NET Core之上。
Microsoft.NETCore.App
元包的目標框架是netcoreapp
。它支持對約60個庫的訪問,其中約40個由NETStandard.Library
提供, 還有約20個其它(標准庫以外的)附加庫。你可以引用基於或兼容netcoreapp
,如netstandard
的附加庫,以獲取對附加庫API的訪問。
大多數由Microsoft.NETCore.App
提供的附加庫,如果這些庫可以很好的依賴其它的netstandard
庫的話,它們也可用於netstandard
。這意味着netstandard libraries
可以添加對這些包的引用。
結語
由於水平有限,翻譯內容難免有錯誤和不足之處,希望大家提出改進意見。文章最后是自己建立.NET Core控制台程序的引用包截圖和項目配置文件,大家可以作為輔助理解文章內容的補充材料。
項目包引用

項目文件
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>netcoreapp1.1</TargetFramework> </PropertyGroup> <ItemGroup> <PackageReference Include="System.Collections.NonGeneric" Version="4.3.0" /> <PackageReference Include="System.IO.FileSystem.AccessControl" Version="4.3.0" /> </ItemGroup> </Project>