NuGet是什么?理解与使用
如果你了解python,那么它類似pip。
如果你了解nodejs,那么它類似npm。
如果你了解ruby,那么它類似gem。
對(duì),它就是一個(gè)包(package)管理平臺(tái),確切的說(shuō)是 .net平臺(tái)的包管理工具,它提供了一系列客戶端用于生成,上傳和使用包(package),以及一個(gè)用于存儲(chǔ)所有包的中心庫(kù)即NuGet Gallery,如果有需要也可以搭建自己的私有NuGet庫(kù)。
NuGet 官方
對(duì)于一個(gè)現(xiàn)代化的開發(fā)平臺(tái),建立一種讓開發(fā)者創(chuàng)建,分享與使用可復(fù)用代碼的機(jī)制是十分必要的。這種“可復(fù)用代碼”被打包后的文件通常被稱作“包”(package),對(duì)于.NET(包括 .NET Core)平臺(tái)來(lái)說(shuō)這個(gè)機(jī)制的實(shí)現(xiàn)就是NuGet平臺(tái)。
NuGet的實(shí)現(xiàn)均為開源項(xiàng)目,包括了客戶端工具,服務(wù)器,官方網(wǎng)站以及各語(yǔ)言的文檔等。這些項(xiàng)目可以在下面的鏈接中找到。
NuGet on GitHub
NuGet包的本質(zhì)是一個(gè)以nupkg為后綴的zip壓縮文件(你可以將后綴改為.zip后解壓查看里面的內(nèi)容),其中包含了編譯后的Dll文件以及其他相關(guān)文件。下圖顯示nuget包從創(chuàng)建,上傳到被使用的流程。
NuGet的客戶端融合在各類開發(fā)工具中,包括但不限于:
.net core SDK中的nuget命令行;
Visual Studio中的nuget工具;
nuget.exe 命令行客戶端;
Visual Studio Code中的nuget插件;
在了解了nuget大致概念后我們可以通過(guò)發(fā)布一個(gè)nuget包來(lái)更仔細(xì)的了解如何使用nuget以及其中的重要概念。
下文會(huì)以開發(fā)中最常接觸到的Visual Studio( 本文使用Visual Studio 2017 Community )做為演示工具來(lái)創(chuàng)建一個(gè)nuget包。要?jiǎng)?chuàng)建一個(gè)包首先需要一個(gè) .net項(xiàng)目,可以看到項(xiàng)目的創(chuàng)建頁(yè)面有很多選擇,類庫(kù)項(xiàng)目就可以選擇三種(.net core的類庫(kù)項(xiàng)目未顯示在截圖中) .Net Core;.Net Framework 還有 .Net Standard,到底應(yīng)該選擇哪一種呢?
Visual Studio 2017 項(xiàng)目創(chuàng)建窗口為了做出選擇,我們首先要深入理解TFMs和 .net standard這兩個(gè)概念。首先創(chuàng)建一個(gè) .net core類庫(kù)項(xiàng)目。
.net core類庫(kù)項(xiàng)目結(jié)構(gòu)在項(xiàng)目目錄中打開csproj文件可以看見下面的內(nèi)容。
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>netcoreapp2.0</TargetFramework> </PropertyGroup></Project>可以看到該項(xiàng)目的TargetFramework為netcoreapp2.0,這里的netcoreapp2.0 就是TFMs,即Tagrget Framework Monikers 翻譯過(guò)來(lái)就是“目標(biāo)框架別名”,這個(gè)值指定了這個(gè)項(xiàng)目是跑在哪個(gè)Framework上的。
如今 .net平臺(tái)有各種版本的Framework,在 .net core之前有 .Net Framework 1.0一直到現(xiàn)在的4.7等等各種版本, .net core現(xiàn)在有1.0/1.1/2.0/2.1。所有這些版本都有自己的代號(hào)/別名。全部的TFMs可以在下面的鏈接找到。
Target frameworks
這仍然沒有解決我們的問(wèn)題:如何決定使用哪個(gè)Framework?現(xiàn)在需要引入 .Net Standard,它是一個(gè)標(biāo)準(zhǔn), .net API的標(biāo)準(zhǔn),用來(lái)描述每個(gè)Framework的API實(shí)現(xiàn)情況。標(biāo)準(zhǔn)的版本越往后支持的API就越多,也就兼容了之前的版本。
當(dāng)前各個(gè)Framework的 .Net Standard版本如下圖(如果你曾經(jīng)了解Portable Class Libraries(PCL),它已經(jīng)被 .net standard替代了,所以這里不多做說(shuō)明。):
最新的內(nèi)容可以在下面的鏈接中找到。
dotnet/standard
所以要選擇哪個(gè)Framework,首先要確定的是:1)你的項(xiàng)目要使用哪些API?2)你項(xiàng)目要兼容哪些Framework? 總的來(lái)說(shuō):
選擇更高的版本,你將有更多的API可以使用。(更豐富的API)
選擇更低的版本,有更多的項(xiàng)目可以使用你的庫(kù)。(更好的兼容性)
所以 .net standard的選擇原則就是:在API夠用的情況下選擇盡量低的 .net standard標(biāo)準(zhǔn)。這需要根據(jù)實(shí)際的項(xiàng)目需求來(lái)進(jìn)行判斷。
了解了TFMs和 .net standard后我們繞回來(lái)說(shuō)NuGet,創(chuàng)建一個(gè) .net standard 2.0 類庫(kù)項(xiàng)目。
打開csproj我們可以看到
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>netstandard2.0</TargetFramework> </PropertyGroup></Project>可以看到TargetFramework是netstandard2.0。如果我們需要更改TargetFraamework,可以選擇項(xiàng)目【屬性】在【應(yīng)用程序】頁(yè)面可以進(jìn)行更改。
目標(biāo)框架修改為了演示我們?yōu)轫?xiàng)目添加一個(gè)第三方包Newtonsoft.Json,右鍵點(diǎn)擊項(xiàng)目選擇管理NuGet程序包。
打開后可以在Visual Studio左側(cè)看到下面的界面。
這里顯示了項(xiàng)目已安裝的包,這個(gè)包由我們選擇的Target Framework隱式引用的。現(xiàn)在我們點(diǎn)擊瀏覽,搜索Newtonsoft.Json。
120M的下載量,可見現(xiàn)在json的流行程度點(diǎn)擊安裝。
安裝完成后可以看到程序包管理器輸出以下信息,并且引用中也添加了新的項(xiàng)目。
但是我并沒有在項(xiàng)目文件夾下找到任何Newtonsoft.Json的程序集,包在哪?其實(shí)包被下載到了一個(gè)nuget公共目錄,在我的Windows10系統(tǒng)上是 C:\Users\wangl\.nuget\packages,這樣nuget包就不會(huì)被重復(fù)下載。而在項(xiàng)目中nuget僅僅將依賴信息寫入了csproj項(xiàng)目文件與obj文件夾中的project.assets.json,其中csproj項(xiàng)目文件中的內(nèi)容如下。
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>netstandard2.0</TargetFramework> </PropertyGroup> <ItemGroup> <PackageReference Include="Newtonsoft.Json" Version="11.0.2" /> </ItemGroup></Project>包所依賴的內(nèi)容并不會(huì)被打包到最后的.nupkg文件中,NuGet只是將依賴信息寫入包,在最終使用這些包的應(yīng)用程序編譯時(shí)還原所有的依賴。
至此我們簡(jiǎn)單了解了NuGet給項(xiàng)目添加引用的過(guò)程。對(duì)于更復(fù)雜情況的引用,如下圖
項(xiàng)目引用示例這個(gè)項(xiàng)目的依賴樹中有三個(gè)對(duì)B包的引用,而三個(gè)包的版本要求可能是不相同的,但幸好我們只需要關(guān)心我們項(xiàng)目直接引用的包,因?yàn)镹uget會(huì)幫我們管理所有包的依賴并且對(duì)于被多次引用的包,Nuget會(huì)找出滿足該包所有使用者的版本(不過(guò)因?yàn)榘姹疽鬀_突而找不到適合包的情況是有可能的)。如果需要更詳細(xì)的了解nuget如何解析項(xiàng)目包的引用可以前往下面的鏈接。
NuGet Package Dependency Resolution
現(xiàn)在開始打包我們的類庫(kù)項(xiàng)目,首先要為包設(shè)置一些諸如版本,作者等相關(guān)信息。右鍵點(diǎn)擊項(xiàng)目選擇【屬性】,再選擇【打包】頁(yè),可以在這里輸入包的描述信息。
打開csproj項(xiàng)目文件,可以看到這些信息也是保存在其中的。
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>netstandard2.0</TargetFramework> <ApplicationIcon /> <OutputType>Library</OutputType> <StartupObject /> <Authors>FishNo6</Authors> <Company>FishNo6</Company> <Product>DemoPackage</Product> <Version>1.0.1</Version> <AssemblyVersion>1.0.0.1</AssemblyVersion> <FileVersion>1.0.0.1</FileVersion> <Description>This package is a demonstration for Nuget package.</Description> </PropertyGroup> <ItemGroup> <PackageReference Include="Newtonsoft.Json" Version="11.0.2" /> </ItemGroup></Project>填寫好信息后保存。回到解決方案,右鍵點(diǎn)擊項(xiàng)目選擇【打包】,可以看到以下輸出。
1>------ 已啟動(dòng)生成: 項(xiàng)目: FishNo6.DemoPackage, 配置: Debug Any CPU ------1>FishNo6.DemoPackage -> E:\labs\FishNo6.DemoPackage\FishNo6.DemoPackage\bin\Debug\netstandard2.0\FishNo6.DemoPackage.dll1>已成功創(chuàng)建包“E:\labs\FishNo6.DemoPackage\FishNo6.DemoPackage\bin\Debug\FishNo6.DemoPackage.1.0.1.nupkg”。========== 生成: 成功 1 個(gè),失敗 0 個(gè),最新 0 個(gè),跳過(guò) 0 個(gè) ==========在對(duì)應(yīng)目錄就可以找到nupkg包文件了。如果你的電腦安裝了NuGet Package Explorer可以直接雙擊打開包來(lái)查看信息,這個(gè)應(yīng)用可以在Window Store中安裝。
到此我們成功創(chuàng)建了一個(gè)NuGet包。
下篇內(nèi)容包括如何將包上傳到NuGet Gallary(NuGet官方庫(kù))以及更深入的了解NuGet平臺(tái)。
最后附上NuGet官方文檔。
NuGet Documentation
那么開始,
一,如何解讀NuGet Gallery上的包信息?
我們先以Newtonsoft.Json為例,在其NuGet頁(yè)面上可以看到如下頁(yè)面,其中包含了作者,描述,依賴等等信息。
其中重要的依賴關(guān)系(部分)如下,
較大字體顯示內(nèi)容如.NETFramework 2.0表示Target Framework(目標(biāo)框架),在Target Framework下面的為此Target Framework對(duì)應(yīng)的依賴,所以用一句話可以解讀為:“如果你項(xiàng)目的目標(biāo)框架也是.NETFramework 2.0,那么你就不需要依賴任何其它包就可以使用這個(gè)包”。同樣的下面.NETFramework 1.0的含義就是:“如果你的項(xiàng)目的目標(biāo)框架為.NETFramework 1.0那么需要引用下面的包后才能使用該包。”不過(guò)這些都不需要你手動(dòng)去引用,NuGet會(huì)在你安裝該包時(shí)自動(dòng)安裝其依賴的包。
Newtonsoft.Json這樣的包是NuGet平臺(tái)上的典型,除此之外還有一些比較特殊但也非常重要的包。我們來(lái)看一下Microsoft.NETCore.Platforms,下面是這個(gè)包的頁(yè)面。
可以看到這個(gè)包竟然沒有任何依賴,這是因?yàn)檫@個(gè)包并不包含任何DLL,所以也不需要依賴任何目標(biāo)框架,NuGet的包可以包含任何你想發(fā)布的文件而不僅僅是DLL程序集。
下面在介紹另一種比較特殊的包,元包(Meta Package), Microsoft.AspNetCore.All就是一個(gè)元包 ,下面是它的頁(yè)面。
頁(yè)面上顯示和普通的包并沒有區(qū)別,為了更直觀的演示我們把這個(gè)包的nupkg文件下載到本地,解壓后可以看到在其lib目錄下面只包含了一個(gè)空文件。
其實(shí)這個(gè)包本身并不包含內(nèi)容,它通過(guò)對(duì)其他包的依賴定義自己。元包是一個(gè)NuGet包的約定,描述了一組放在一起有意義的包(Metapackages are a NuGet package convention for describing a set of packages that are meaningful together.)
這樣做的原因首先是因?yàn)镹uGet的包管理是“細(xì)粒度”的,原則上每個(gè)程序集(DLL)都應(yīng)該是一個(gè)包,這樣可以帶來(lái)以下幾個(gè)好處:
細(xì)粒度的包在開發(fā)、測(cè)試的過(guò)程中與其它包的關(guān)聯(lián)有限。
細(xì)粒度的包可以提供對(duì)不同操作系統(tǒng)和CPU的支持。
細(xì)粒度的包可以只依賴某個(gè)特定的庫(kù)。
在發(fā)布應(yīng)用時(shí),未被引用的包不會(huì)成為應(yīng)用的一部分,因此應(yīng)用程序的體積會(huì)有更小。
但是對(duì)于某些情況,元包則有更多好處:
在引用大量細(xì)粒度包時(shí)有更好的用戶體驗(yàn)
定義了一組經(jīng)過(guò)測(cè)試且運(yùn)行良好的包(包括指定的各種版本)
而下面這個(gè)元包比較特殊:Microsoft.NETCore.App,因?yàn)樗粌H是元包也定義了框架,也就是我們項(xiàng)目里的目標(biāo)框架(Tagrget Framework)。這會(huì)在解讀這類目標(biāo)框架的元包時(shí)造成一定的困惑,以 Microsoft.NETCore.App上的頁(yè)面為例,因?yàn)樗旧矶x了目標(biāo)框架。不過(guò)我們應(yīng)該不會(huì)手動(dòng)去引用這些包,這些包通常是在是設(shè)置目標(biāo)框架是被項(xiàng)目隱式應(yīng)用的。
下面這張圖描述了這種關(guān)系:API定義了框架,框架用于元包中包的選擇,而這些包給你提供了API的實(shí)現(xiàn)。
更多資料可以查看下面這篇文章和其中文譯文,對(duì)你理解NuGet平臺(tái)和包,元包,框架的設(shè)計(jì)很有幫助。
Packages, metapackages and frameworks
二,如何上傳NuGet包?
要上傳NuGet包到NuGet Gallery,首先你需要一個(gè)NuGet賬號(hào)或者微軟賬號(hào),然后準(zhǔn)備好你的nupkg文件就可以開始上傳了。
下面簡(jiǎn)單介紹三種方式:
1,在NuGet Gallery網(wǎng)頁(yè)上傳包,這是最方便快捷的方式。登錄NuGet Gallery 點(diǎn)擊Upload菜單進(jìn)入上傳頁(yè)面。
nuget gallery包上傳頁(yè)面點(diǎn)擊Browse選擇你的包文件,頁(yè)面將讀取你的包信息并顯示在頁(yè)面上。
填寫包的文檔相關(guān)信息。
填寫包的文檔相關(guān)信息確保所有信息正確后就可以點(diǎn)擊Submit發(fā)布你的包了!
2,在NuGet Package Expolrer中上傳包,這個(gè)應(yīng)用可以在Windows Store中免費(fèi)安裝。在使用該工具上傳包之前你需要一個(gè)API Key,因?yàn)槌褂霉俜缴蟼黜?yè)面的方式外所有其他方式上傳包都需要使用一個(gè)API Key,這個(gè)Key可以在官方網(wǎng)站獲取。在個(gè)人帳號(hào)的下拉菜單中選擇API Keys。
進(jìn)入API Key管理頁(yè)面,點(diǎn)擊如下圖的Create,開始創(chuàng)建一個(gè)API Key。
填寫好Key的名稱,過(guò)期時(shí)間,再選擇該Key可以使用的功能和對(duì)應(yīng)的包,點(diǎn)擊確認(rèn)成功創(chuàng)建后可以看到如下圖的頁(yè)面。
點(diǎn)擊Copy就可以拷貝你的Key到剪貼板。有了API Key之后我們使用NuGet Explorer打開我們的包,在File菜單中選擇Publish.
點(diǎn)擊Publish后出現(xiàn)如下界面。
輸入所需的API Key點(diǎn)擊Publish。
3,使用 .net core SDK命令行上傳包,可以執(zhí)行dotnet nuget push的命令,其中第一個(gè)參數(shù)為包所在目錄,若再當(dāng)前目錄可直接填入文件名, -k參數(shù)就是我們?cè)谏厦嫠@取到的API Key,如下面的命令行示例。
dotnet nuget push foo.nupkg -k 4003d786-cc37-4004-bfdf-c4f3e8ef9b3a該命令還有許多其他參數(shù),更多信息可前往下面的鏈接:
dotnet nuget push command - .NET Core CLI
需要注意的是包上傳后是不能被刪除的,只能被unlist。鑒于此我沒有真的上傳我的包,因?yàn)橹酪粋€(gè)完全沒有意義的包在我的賬號(hào)里還無(wú)法刪除會(huì)讓我寢食難安的。大家可以自己動(dòng)手嘗試。
三,如何安裝本地NuGet包?
以Visual Studio 2017 Community為例,打開你的項(xiàng)目,右鍵點(diǎn)擊項(xiàng)目選擇【管理NuGet程序包】。
然后點(diǎn)擊NuGet程序包管理界面右上角的齒輪,出現(xiàn)下面的設(shè)置窗口。
點(diǎn)擊+號(hào)新建一個(gè)可用程序包源,設(shè)置你想要的名稱并選擇源的所在目錄,點(diǎn)擊確定。
再次打開NuGet程序包器,你可以在程序包源選項(xiàng)中看到看添加的源,選中后就可以看到你在該本地路徑中放置的包了!
四,NuGet包的內(nèi)容與目錄結(jié)構(gòu)?
我們?nèi)砸訬ewtonsoft.Json包為例,將后綴改為.zip并解壓后可以看到以下目錄結(jié)構(gòu)。
其中l(wèi)ib目錄如下圖,它保存了各個(gè)目標(biāo)框架下對(duì)應(yīng)的程序集。
Newtonsoft.Json.nuspec為xml格式的manifest文件保存了包的元數(shù)據(jù),如作者,版本,包含內(nèi)容等等信息。rels,[Content_Types].xml,package為打包時(shí)生成的文件。
除了這些目錄外,包內(nèi)還可以包含runtimes,content,build,tools等文件夾,下面介紹runtimes和content文件夾。
如果你的程序集對(duì)不同的操作系統(tǒng)有不同的實(shí)現(xiàn),你需要將這些程序集按照下面的目錄結(jié)構(gòu)放入runtimes文件夾中。
\runtimes \win10-arm \native \lib\uap10.0 \win10-x86 \native \lib\uap10.0 \win10-x64 \native \lib\uap10.0而對(duì)于content文件夾,你可以把它看做是目標(biāo)項(xiàng)目的根目錄,也就是該文件夾下的內(nèi)容會(huì)在包被安裝時(shí)拷貝到項(xiàng)目的目錄下。比如包里的content/images目錄在包被安裝之后就會(huì)在你的項(xiàng)目目錄下放置一個(gè)images目錄。
除了這些主要的文件夾,NuGet包里還可以包含build,tools等文件夾和文件,更多詳細(xì)內(nèi)容可查看下面的文檔。
How to create a NuGet package
希望本篇能讓你對(duì).net的包管理平臺(tái)有基本的了解,利用好NuGet平臺(tái)會(huì)給你以后的項(xiàng)目開發(fā)提供很大的幫助。
原文地址:https://zhuanlan.zhihu.com/p/36767572
.NET社區(qū)新聞,深度好文,歡迎訪問(wèn)公眾號(hào)文章匯總?http://www.csharpkit.com?
總結(jié)
以上是生活随笔為你收集整理的NuGet是什么?理解与使用的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: C# 8.x 先睹为快
- 下一篇: 你竟然没用 Nuget 构建项目?