- https://docs.nuget.org/Create/Creating-and-Publishing-a-Package
- https://docs.nuget.org/Create/Enforced-Package-Conventions
基本步驟
- 使用 nuget spec 命令生成 nuspec 文件
- 編輯 nuspec 文件,使用 nuget pack 命令打包
從程序集創建程序包
執行以下命令:生成 nuspec 文件:
nuget spec MyAssembly.dll
按需編輯 nuspec 文件后執行打包命令:
nuget pack MyAssembly.nuspec
從項目文件創建程序包
在項目文件夾執行:
nuget spec
工具會讀取 csproj 或 vbproj 文件生成 nuspec 文件。這種方式生成的 nuspec 文件包含一些可替換標記,打包時會用項目的元數據替換標記。可用標記包括:
- $id$ 用程序集名稱替換
- $version$ 用 AssemblyVersionAttribute 或 AssemblyInformationalVersionAttribute 替換
- $author$ 用 AssemblyCompanyAttribute 替換
- $description$ 用 AssemblyDescriptionAttribute 替換
若不需要自動替換,可手工移除這些標記。
注意,使用項目文件執行打包命令才會替換這些標記,使用 nuspec 文件執行打包命令不會替換。
使用 files 節點顯式指定程序包中包含哪些文件,例如:
<files> <file src="..\..\SomeRoot\**\*.*" target="" /> </files>
程序包將僅包含這個節點中指定的文件,若 files 節點為空,則程序包將僅包含 lib 文件夾。另外 pack 命令會排除已句點開頭的目錄,例如 .git。
編輯好 nuspec 文件后,執行打包命令:
nuget pack MyProject.csproj
如果項目引用其他項目,可使用 -IncludeReferencedProjects 選項包含被引用項目的文件。假設有下圖所示的引用結構:
執行命令
nuget pack A.csproj -IncludeReferencedProjects
生成的程序包會包含項目 A,B,C,D,E,F,G中的文件。
如果被引用的項目有 nuspec 文件,則它將作為依賴項,例如 C.csproj 所在目錄中有一個 C.nuspec 文件,執行以上命令后生成的程序包將包含項目 A,B,D,E 中的文件,並且有一個對 C 的依賴項。
默認情況下,NuGet 使用默認生成配置(通常是Debug),要打包 Release 配置的文件,可執行:
nuget pack MyProject.csproj -Prop Configuration=Release
visual studio 未提供修改默認生成配置的界面,要修改默認生成配置,需要手工編輯項目文件。
在生成時創建程序包
通過添加 AfterBuild 目標,可以在生成成功時自動創建程序包。手工編輯項目文件,加入以下內容:
<Target Name="AfterBuild" Condition=" '$(Configuration)' == 'Release'"> <Exec Command="nuget pack $(ProjectFileName) -Prop Configuration=Release"></Exec> </Target>
將在生成配置為 Release 時自動調用 nuget.exe 創建程序包。
從基於約定的目錄創建程序包
除了程序集,程序包中還可包含源代碼,PowerShell 腳本,可執行文件,配置文件等內容。NuGet 有一個對工作目錄結構的約定:
- tools。用於存放 powershell 腳本,以及可在程序包管理器控制台訪問的程序。這個目錄復制到目標項目后,將添加到 `$env:Path (PATH) 環境變量。
- lib。安裝程序包時,此文件夾下的程序集作為引用添加到目標項目。
- content。安裝程序包時,這個文件夾下的文件將復制到目標項目的根目錄。
- build。安裝程序包時,自動插入到 .csproj 文件。
可以把 content 目錄想象成目標項目的根目錄。如果要在目標項目的 /images 目錄添加一個圖片文件,那么應把這個圖片放在程序包的 content/images 文件夾中。
創建清單
請執行以下命令從頭創建一個 spec 文件
nuget spec
將生成一個 XML 格式的 .nuspec 文件。
<?xml version="1.0"?> <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd"> <metadata> <id>MyPackageId</id> <version>1.0</version> <authors>philha</authors> <owners>philha</owners> <licenseUrl>http://LICENSE_URL_HERE_OR_DELETE_THIS_LINE</licenseUrl> <projectUrl>http://PROJECT_URL_HERE_OR_DELETE_THIS_LINE</projectUrl> <iconUrl>http://ICON_URL_HERE_OR_DELETE_THIS_LINE</iconUrl> <requireLicenseAcceptance>false</requireLicenseAcceptance> <description>Package description</description> <tags>Tag1 Tag2</tags> <dependencies> <dependency id="SampleDependency" version="1.0" /> </dependencies> </metadata> </package>
將文件中的占位符改成實際的值,然后創建需要的目錄並復制內容
mkdir lib mkdir tools mkdir content mkdir content\controllers copy ..\src\SomeController.cs content copy ..\src\MyLibrary lib copy ..\src\SomePowershellScript.ps1 tools
准備好工作目錄后,執行:
nuget pack YourPackage.nuspec
來打包文件。采用這種方式創建程序包不支持標記替換功能。
創建解決方案級程序包
解決方案級程序包用於向程序包管理器控制台按照工具或額外命令,但不添加引用,內容,也不修改生成過程。例如,psake 程序包安裝 powershell 腳本幫助自動化生成過程。
如果程序包在 lib, content, build 目錄中都沒有文件,它就是解決方案級的,被它依賴項同樣不能在 lib, content, build 目錄中包含文件。
已安裝的解決方案級程序包在 .nuget 目錄的 package.config 文件中跟蹤,而不是在特定項目的的 packages.config 文件中跟蹤。
NuGet 3.0.0-3.2.0 不支持解決方案級程序包,變通的方式是安裝到公共項目中。
程序包約定
框架版本文件夾結構
安裝程序包時,NuGet 檢查項目的目標框架,然后從 lib 文件夾中選擇合適的子文件夾。使用以下命名約定指示程序集安裝到哪個框架:
lib\{framework name}{version}
例如,下面的文件夾結構支持四個版本
\lib \net11 \MyAssembly.dll \net20 \MyAssembly.dll \net40 \MyAssembly.dll \sl40 \MyAssembly.dll
從 NuGet 2.0 開始,內容文件和 powershell 腳本也可按照目標框架分組,規則同 lib 文件夾。
\content \net11 \MyContent.txt \net20 \MyContent20.txt \net40 \sl40 \MySilverlightContent.html \tools init.ps1 \net40 install.ps1 uninstall.ps1 \sl40 install.ps1 uninstall.ps1
init.ps1 在解決方案級運行,與項目和目標框架無關,應直接放在 tools 文件夾中。
框架名稱
NuGet 將文件夾名解析為 FrameworkName 對象,名稱是區分大小寫的,名稱和版本號都可以使用縮寫形式。
如果省略框架名稱,則假定是 .Net Framework。例如,以下文件夾結構與上面的同義:
\lib \11 \MyAssembly.dll \20 \MyAssembly.dll \40 \MyAssembly.dll \sl4 \MyAssembly.dll
下表是有效的框架名稱和縮寫
框架名稱 | 縮寫 |
.NET Framework | net |
Silverlight | sl |
.NETMicroFramework | netmf |
Windows Store | win |
Windows Phone (Silverlight-based) | wp |
Windows Phone App (WinRT-based) | wpa |
框架版本無關的程序集
與框架版本無關的程序集直接放在 lib 文件夾中。
程序集版本和項目的目標框架的匹配
向項目安裝具有多個程序集的程序包時,NuGet 會將程序集的框架名稱同項目的目標框架進行匹配。若未找到匹配,NuGet 會排除大於項目框架版本的程序集,然后從剩余的程序集中選擇最高版本。假設要把上例中的程序包安裝到以 .net 3.5 為目標的項目中,實際安裝的是 net20 文件夾中的程序集。
按照框架版本對程序集進行分組
NuGet 僅從一個庫目錄中復制文件,假設有以下目錄
\lib \Net20 \MyAssembly.dll (v1.0) \MyAssembly.Core.dll (v1.0) \Net40 \MyAssembly.dll (v2.0)
安裝到以 .net4 為目標的項目時,僅安裝 MyAssembly.dll (v2.0),不安裝 MyAssembly.Core.dll (v1.0) 。若要安裝 MyAssembly.Core.dll,要在 net40 中再包含一次。
僅從一個目錄復制的規則也適用於根 lib 文件夾。有以下文件夾結構
\lib \MyAssembly.dll (v1.0) \MyAssembly.Core.dll (v1.0) \Net40 \MyAssembly.dll (v2.0)
對於以 .net2.0 或 3.5 為目標的項目,NuGet 復制 MyAssembly.dll 和 MyAssembly.Core.dll。對於以 .net4.0為目標的項目,則僅復制 net40 中的 MyAssembly.dll。
在安裝和卸載時自動運行 PowerShell 腳本
NuGet 按照命名約定自動運行 PowerShell 腳本:
- Init.ps1 當程序包首次安裝到解決方案后運行。
- 程序包到解決方案的其他項目時不會運行。
- 每次打開解決方案都會運行(程序包管理器控制台窗口必須打開)。
- Install.ps1 當程序包安裝到項目后運行。
- 如果程序包安裝到解決方案中的多個項目時,將為每個項目運行一次。
- 程序包的 content 或 lib 目錄存在文件時才會運行。僅在 tools 文件夾中存在文件不會運行。
- 若 init.ps1 存在,install.ps2 在 init.ps1 之后運行。
- [NuGet 3.x] 在使用 project.json 管理的項目中不運行。
- Uninstall.ps1 在程序包卸載后運行。
- [NuGet 3.x] 在使用 project.json 管理的項目中不運行。
- 腳本文件應放在程序包的 tools 目錄中。
- 在文件頂部加上這樣一行:param($installPath, $toolsPath, $package, $project)
- $installPath 是安裝目錄。
- $toolsPath 是安裝目錄下的 tools 目錄。
- $package 是程序包對象的引用。
- $project 是 EnvDTE 項目對象的引用,它表示程序包安裝到的項目。init.ps1 在解決方案級運行,因此 init.ps1 中為 null。
- 編寫腳本時,若要在控制台測試 $project,可設置為 $project = Get-Project。
可通過 NuGetPSVariables 程序包了解實際的輸出,這個工具將信息寫到日志中:
Install-Package NuGetPSVariables
NuGetPSVariables 程序包在顯示日志文件后自動卸載。