本文翻譯自 Packages, Metapackages and Frameworks。javascript
.Net Core 是一種由 NuGet 包組成的平臺。一些產品體驗受益於代碼包的細粒度定義,而另外一些受益於粗粒度的定義,這兩種定義都是有用的,不能絕對地說哪一個好與很差。所以,爲了適應這兩種區別,一款好的產品應該能夠被拆分紅一組一組的細粒度的代碼包,這些包之間相互獨立,單個代碼包的正式的名字叫作「元包」(metapackage)。java
每一個.Net Core 包都支持運行於多種 .Net 運行時中,這些運行時被稱爲 「框架」(framework)。其中有的框架是傳統框架,例如 net46;而另外一些則是新的框架,能夠認爲它們是「基於包的框架」,這種是框架的另一種新的定義模型。這些基於包的框架整個都是由包組成的,它們自身也被定義成包,這就在框架與包之間造成了一種比較密切的關係。ios
.Net Core被分割成爲一組包,它們提供了基元類型,以及更高層的數據類型,應用組合類型,以及公共的類庫。每個包都表明着單獨的同名程序集,例如,System.Runtime 這個包,就包含了 System.Runtime.dll 這個程序集。json
把這些包定義成爲細粒度的結構風格,有如下好處:網絡
上述好處僅適用於某些特定的場合。好比,Net Core 的全部包會在同一個發佈週期內提供對同一個平臺的支持,在這種狀況下,補丁與更新會以小的單獨包的形式發佈。因爲這種小範圍的變化,補丁的驗證與相關工做,均可以限制到單個平臺與類庫的需求範圍中,這樣一來,就能夠把工做最小化。app
如下是 基於 NuGet 庫的 .Net Core 包清單:框架
包引用在 project.json 文件中定義,在下面的例子中,使用了 System.Runtime 包:測試
{ "dependencies": { "System.Runtime": "4.1.0" }, "frameworks": { "netstandard1.5": {} } }
在大部分狀況下,你可能不須要直接引用底層的 .Net Core 包,由於引用的包太多了會讓你抓狂。因此你只須要引用元包。spa
元包就是一個 NuGet 包,方便地描述了一組意義相關的包。開發團隊利用依賴關係來描述一組包,他們經過這一組包來描述一個框架(framework),而後有選擇地發佈出去。翻譯
引用一個元包,這個操做,實際上添加了對元包中每個獨立包的引用依賴,這意味着這些包中全部的類庫(refs 或者 libs)都會在智能感知(IntelliSense)中可用,同時也會發布(lib目錄)到你的應用中。
注意: lib 與 ref 指的是 NuGet 包中的相應的文件夾, ref 目錄描述的是以元程序集表示的公共API包,lib 目錄 包含了這個公共API的在不一樣框架下的實現。
使用元包有如下好處:
.Net 標準類庫元包:
如下是 .Net Core 元包:
元包的引用方法就像普通的 NuGet包同樣,在 project.json 中定義。
在下面的例子中, 引用了 NETStandard.Library 這個元包,用來建立一個基於 .Net 運行時的可移植類庫。
{ "dependencies": { "NETStandard.Library": "1.5.0" }, "frameworks": { "netstandard1.5": {} } }
在下面的例子中,引用了 Microsoft.NETCore.App 這個元包,用來建立應用或者是類庫,運行於 .Net Core之上,而且充分使用 .Net Core 全部功能。它提供的訪問範圍,要比 NetStandard.Library 更大。
{ "dependencies": { "Microsoft.NETCore.App": "1.0.0" }, "frameworks": { "netcoreapp1.0": {} } }
每個 .Net Core 包都支持一組框架,在框架文件夾中進行聲明(就在前面所說的 lib 與 ref目錄中)。框架描述了一組可用的API(以及潛在的其餘特性),因此你能夠在指定一個目標框架時獲得這些功能。當新的API加入時,就會進入版本管理流程。
例如, System.IO.FileSystem 支持如下框架:
頗有必要對前兩種框架進行對比,由於它們各自表明了一種不一樣的框架定義方式。
.NETFramework,Version=4.6 這個框架表明了在 .Net Framework 4.6 中可用的API,你能夠根據這些API生產本身的類庫,引用其中的程序集,並以NuGet包的方發佈你的類庫,發佈後它們會位於lib文件夾下一個名爲 net46 的文件夾中。這樣,你的
類庫就會被那些基於或者兼容 .Net Framework 4.6 的應用程序所使用。這是傳統類庫的工做方式。
而.NETStandard,Version=1.3這個框架是一個基於包的框架。那些以此框架爲目標的包,定義而且實現的API,就組成了這個框架。
可見它們的區別:傳統的框架是事先定義好的一個總體,而基於包的框架,則能夠對不一樣的包自由組合。
框架與包之間的關係是雙向的。
首先是爲一個給定的框架定義了一組API,如 netstandard1.3。以 netstandard1.3 爲目標的包(或者兼容框架,如netstandard1.0)定義了哪些API是可使用的,聽起來像是循環定義,然而並非。從 「基於包的」這個詞自己的角度來說,框架的API定義是來自於包的,框架自己並不定義任何API。
其次,是這個雙向關係中的資產選擇。包內部能夠含有不一樣框架的資產,對於一組包或者元包的引用,框架須要決定它應選擇哪些資產,例如,是 net46 仍是 netstandard1.3。對於交叉資產來講,這個很是重要,例如,一個 net46 的資產可能並不會與 .Net Framework 4.0 或者 .Net Core 1.0 兼容。
你能夠在上圖中看到這種關係,API 選擇 框架 做爲目標,而且API定義了框架, 而框架用於資產選擇,資產實現了API。
這裏出現了一個有趣的問題:框架定義的結束之處,正是消費開始的地方。能夠把框架當作是由 project.json 文件給出的功能定義,你所依賴的東西建立了實際上的框架,這個框架獨立於那些已經發布出來的完整框架的依賴項。(譯者注:能夠這麼理解,
框架的實際實現取決於你在 project.json 中引用的東西,可能你並不會引用全部的包,因此你所依賴的包是官方框架的所有包的一個子集。)
在.Net Core基礎之上,基於包的框架主要有兩個:
.NET 標準框架(netstandard)意指基於 .Net 標準類庫所定義與構建的API。若是你所構建的類庫將會用於多種運行平臺,應該以基於netstandard進行構建,這樣類庫就會支持任何一種 兼容 .Net 標準的運行時,好比 .Net Core, .Net Framework以及 Mono/Xamarin。這些運行時中的每一處都支持一種或幾種 .Net 標準,至於到底支持哪一個版本,則取決於具體實現。
元包 NETStandard.Library 的目標框架是 netstandard。要以 netstandard 爲目標框架,最多見的方法是引用此元包。它定義與提供了約40個.Net類庫,並與.Net 標準類庫所定義的API相關聯。你能夠引用基於 netstandard 開發的第三方包來使用第三方API。
一個給定的 NETStandard.Library 版本,老是與 netstandard 所公開的最高版本相匹配。 project.json 文件中對於框架的引用,主要是用來今後框架中選擇正確的資產。所以,假如定義了 netstandard1.5,就須要 其中的dll資產,而不是 netstandard1.4,或者 net46。
{ "dependencies": { "NETStandard.Library": "1.5.0" }, "frameworks": { "netstandard1.5": {} } }
這個 project.json 文件中所引用的 框架與元包 並不須要嚴格匹配,例以下面的 project.json 也是正確的:
{ "dependencies": { "NETStandard.Library": "1.5.0" }, "frameworks": { "netstandard1.3": {} } }
把構建目標設置爲 netstandard1.3 卻使用 NETStandard.Library 的 1.5 版本,彷佛有點奇怪。然而這是一個合法的用例,由於元包支持更老的 netstandard 版本。可能剛好 你使用了 1.5.0 的元包版原本開發你全部的類庫,而後運行於多種版本的 netstandard,在這種狀況下,你只須要從新加載 NETStandard.Library 1.5.0 便可,並不須要加載早期版本。
反之則並不成立:把 netstandard1.5 做爲運行目標,卻使用 NETStandard.Library 的 1.3.0 版原本開發你的類庫:你不可以把更高版本的框架做爲開發目標,卻使用更低版本的元包。元包資產的版本管理機制,與框架的最高版本的定義相匹配。藉助於版本管理機制,NETStandard.Library 的第一個版本是 v1.5.0,它包含了 netstandard1.5 的資產。而上面例子中的 v1.3.0 版本,只是爲了舉例方便,實際上並不存在。
譯者注:這一段的各類名詞相互繞來繞去,會把人繞暈。舉個例子就明白了:由於類庫老是向下兼容的,1.5 的實現必然包含了1.3的全部定義,1.5 版本的元包,是能夠運行於 1.3 版本的框架之上。
然而這與咱們的直覺經驗不符,所以做者說看起來很奇怪,由於你在 Win7 上開發的程序(依賴高版本元包),極可能不支持運行在 XP 系統上(低版本框架)。
可是爲何在神奇的 .Net Core 的世界中,這個現象就發生了呢?
這是由 .Net Core 的版本管理機制所決定的。文中並無給出來具體的解釋。關於版本管理,有另一篇文章會介紹,稍後翻譯。
.NET Core Application 框架(netcoreapp) 意爲: 包與相關的API是 基於.Net Core 特定發佈版本以及它所提供的控制檯程序模型。.Net Core應用程序必須使用這個框架,由於必需要使用其中的控制檯程序模型。同時只運行於 .Net Core 平臺的類庫也應使用這個模型。使用這框架之後,應用程序(exe)與類庫(dll)將只可以運行於.Net Core平臺上。(老外好囉嗦啊) 元包 Microsoft.NETCore.App 的目標框架是 netcoreapp 。此元包提供了約 60 個類庫,其中大約 40 個是由 NETStandard.Library 提供的,另外20個是由 Microsoft.NETCore.App 本身實現的(addition)。若是你開發的類庫的目標框架是 netcoreapp 或其兼容框架(如netstandard),則可使用 Microsoft.NETCore.App 的這些20個額外類庫(addition),來調用這些額外的API。
譯註:addition,是指由 Microsoft.NETCore.App 在 NETStandard.Library 基礎之上的額外實現,約20個類庫。在從傳統 Framework遷移過來的代碼中,若是你使用了 NETStandard.Library ,可能會出現不識別類或者方法的狀況,頗有多是由於這些不識別的部分實如今這20個addition中,改成引用 Microsoft.NETCore.App 可能會解決問題。
由 Microsoft.NETCore.App 額外實現的大部分類庫,也能夠運行於 其餘的 netstandard 框架,若是這些框架知足了它們所依賴的類庫的運行環境的話。這意味着 運行於 netstandard 框架的類庫也引用這些額外包做爲依賴項。
譯註:這段話也比較晦澀,再舉例子說明。例如 Microsoft.NETCore.App 1.5 (簡稱App1.5)是 在 NETStandard.Library 1.5 (簡稱Lib1.5)之上實現了額外20個包(Add20),即 App1.5 = Lib1.5 + Add20。 前面說 Lib1.5 能夠運行於框架 netstandard 1.5(簡稱 Std1.5),以及 Std1.3 之上,若是這個 Add20 也能夠運行於 Lib1.3 的話,那麼就能夠獲得 App1.5 也能夠運行於 Lib1.3。