乘风破浪,遇见最佳跨平台跨终端框架.Net Core/.Net生态 - 面向所有项目风格的Nuget打包发布/离线部署(.NET Framework、.NET Standard)

什么是Nuget

NuGet是Microsoft开发平台的程序集包管理器,它由客户端工具和服务端站点组成,客户端工具提供给用户管理和安装/卸载软件程序包,以及打包和发布程序包到NuGet服务端站点等功能,服务端站点存储已经发行的软件包,并为NuGet客户端软件包库提供服务,使软件包共享给其他的开发者。

适用于任何现代开发平台的基本工具可充当一种机制,通过这种机制,开发人员可以创建、共享和使用有用的代码。通常,此类代码捆绑到“包”中,其中包含编译的代码(如DLL)以及在使用这些包的项目中所需的其他内容。

对于.NET(包括.NET Core),共享代码的Microsoft支持的机制则为NuGet ,其定义如何创建、托管和使用面向.NET的包,并针对每个角色提供适用工具。

简单来说,NuGet 包是具有.nupkg扩展的单个ZIP文件,此扩展包含编译代码(Dll)、与该代码相关的其他文件以及描述性清单(包含包版本号等信息)。 使用代码的开发人员共享创建包,并将其发布到公用或专用主机。 包使用者从适合的主机获取这些包,将它们添加到项目,然后在其项目代码中调用包的功能。 随后,NuGet自身负责处理所有中间详细信息。

image

由于NuGet支持公用nuget.org主机旁边的专用主机,因此,可以使用NuGet包来共享组织或工作组专用的代码。 此外,你还可以使用NuGet包作为一种便捷的方式,将自己的代码用于除你自己项目之外的任何其他项目。 简而言之,NuGet包是可共享的代码单元,但不需要暗示任何特定的共享方式。

识别项目格式

NuGet适用于所有.NET项目。但是,项目格式(SDK样式或非SDK样式)决定了使用和创建NuGet包所需的一些工具和方法。SDK样式的项目使用SDK属性。确定项目类型非常重要,因为用于使用和创建NuGet包的方法和工具都依赖于项目格式。对于非SDK样式的项目,方法和工具还取决于项目是否迁移到PackageReference格式。

项目类型 默认项目格式 CLI工具
.NET Standard SDK样式 dotnet CLI
.NET Core SDK样式 dotnet CLI
.NET Framework 非SDK样式 nuget.exe CLI

手动识别

使用Visual Studio Code打开*.csproj,如果Project节点,存在属性Sdk基本上就是SDK样式的。

SDK样式示例

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
  </PropertyGroup>

</Project>

非SDK样式示例

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />

差异点

非SDK样式项目文件夹,我们发现,它会有一个Properties文件夹,里面有个我们熟知的AssemblyInfo.cs记录了这个项目的信息。

image

using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

// 有关程序集的一般信息由以下
// 控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("ExampleWinforms")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ExampleWinforms")]
[assembly: AssemblyCopyright("Copyright ©  2022")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

// 将 ComVisible 设置为 false 会使此程序集中的类型
//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
//请将此类型的 ComVisible 特性设置为 true。
[assembly: ComVisible(false)]

// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
[assembly: Guid("3f148d75-9dd3-4a79-b72d-a530b0bcbc7f")]

// 程序集的版本信息由下列四个值组成: 
//
//      主版本
//      次版本
//      生成号
//      修订号
//
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
//通过使用 "*",如下所示:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

而在SDK样式项目文件夹,并不存在Properties文件夹,项目信息是直接记录在*.csproj中的。

image

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net6.0-windows</TargetFramework>
    <Nullable>enable</Nullable>
    <UseWindowsForms>true</UseWindowsForms>
    <ImplicitUsings>enable</ImplicitUsings>
    <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
    <Description>测试</Description>
    <Copyright>版权说明</Copyright>
    <PackageProjectUrl>https://www.baidu.com</PackageProjectUrl>
    <AssemblyVersion>1.0.0</AssemblyVersion>
    <FileVersion>1.0.0</FileVersion>
    <PackageReleaseNotes>发行说明</PackageReleaseNotes>
    <RepositoryUrl>git.xxxxxxxxxxxxxxxxxxxxxx</RepositoryUrl>
    <RepositoryType>git</RepositoryType>
    <Title>ExampleWinFormsApp</Title>
    <PackageId>ExampleWinFormsApp</PackageId>
    <Version>1.0.0</Version>
    <Authors>TaylorShi</Authors>
    <Company>TaylorShi Inc.</Company>
  </PropertyGroup>

</Project>

非SDK样式项目打包

对于较为传统的.Net framework的项目,它属于非SDK样式项目,所以对应的打包工具就是nuget.exe

获取Nuget.exe

NuGet.exe 5.0及更高版本需要.NET Framework 4.7.2或更高版本才能执行。

直接从nuget.org官方下载一个即可。

建议是丢C:\Windows目录即可,省去配置什么环境变量。

image

Linux下安装Nuget

sudo apt install mono-runtime

image

先安装Mono 4.4.2+版本,然后执行如下命令:

sudo curl -o /usr/local/bin/nuget.exe https://dist.nuget.org/win-x86-commandline/latest/nuget.exe

image

编辑~/.bash_aliases或者~/.bash_profile,追加如下别名。

sudo vim ~/.bash_aliases
# Create as alias for nuget
alias nuget="mono /usr/local/bin/nuget.exe"

重新进入一次Shell,然后试试nuget ?来验证安装。

自我更新Nuget.exe

如果你之前已经安装过它,还可以调用它自己的命令来更新它,因为前面我们放到C:\Windows目录,所以这里需要用管理员运行Windows Terminal。

nuget update -self

image

准备项目属性

对非SDK样式项目来说,它的项目属性信息是在项目-属性-程序集信息对话框中设置的,对应的文件是.\Properties\AssemblyInfo.cs

image

把这里面能填的信息都填下,程序集版本和文件版本建议保持一致,等下会作为Nuget包的版本号,前三位就行,最后一位可以是0。

创建Nuget初始清单

在当前这个.csproj目录,执行如下命令:

nuget spec

它会针对.csproj这个项目生成一个初始清单,后缀为*.nuspec

image

编辑补充初始清单

接下来我们可以使用Visual Studio Code,它刚开始的内容差不多是这样:

<?xml version="1.0" encoding="utf-8"?>
<package >
  <metadata>
    <id>$id$</id>
    <version>$version$</version>
    <title>$title$</title>
    <authors>$author$</authors>
    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    <license type="expression">MIT</license>
    <!-- <icon>icon.png</icon> -->
    <projectUrl>http://project_url_here_or_delete_this_line/</projectUrl>
    <description>$description$</description>
    <releaseNotes>Summary of changes made in this release of the package.</releaseNotes>
    <copyright>$copyright$</copyright>
    <tags>Tag1 Tag2</tags>
  </metadata>
</package>

这里面,有些如果有就填,没有的话建议删除掉,比如:

  • projectUrl,将包上传到nuget.org时,字段projectUrl限制为4000个字符,如果有Github或者官网建议填下。
  • releaseNotes,将包上传到nuget.org时,字段releaseNotes限制为35,000个字符。
  • tags,这个建议填一填,方便根据关键词搜索到。

接下来,我们可以给它弄个图标,这样好看点。

首先我们需要准备一个图标文件,比如就叫icon.png,把它放到.csproj目录,官方建议是128x128的PNG或者JPEG格式,体积小于1MB。

image

然后我们需要声明这个图标File文件,比如:

<files>
  <file src=".\icon.png" target="images\" />
</files>

这里src就填相对目录就可以了,这个target其实有点像个命名空间,意味着这个png挂在images\下面了,所以在<icon>那里应该写成:

<icon>images\icon.png</icon>

如果你想要Nuget.org上呈现更精彩格式的说明,也可以内置一个markdown进来,先准备一个名为readme.md的文件,里面先随便写点。

image

然后以文件形式加进来

<files>
  <file src=".\readme.md" target="docs\" />
</files>

readme节点添加进来

<readme>docs\readme.md</readme>

最终效果:

<?xml version="1.0" encoding="utf-8"?>
<package >
  <metadata>
    <id>$id$</id>
    <version>$version$</version>
    <title>$title$</title>
    <authors>$author$</authors>
    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    <license type="expression">MIT</license>
    <icon>images\icon.png</icon>
    <readme>docs\readme.md</readme>
    <projectUrl>https://www.nuget.org/packages?q=Microsoft.Extensions.Logging</projectUrl>
    <description>$description$</description>
    <releaseNotes>Summary of changes made in this release of the package.</releaseNotes>
    <copyright>$copyright$</copyright>
    <tags>Microsoft TestPackage</tags>
  </metadata>
  <files>
    <file src=".\icon.png" target="images\" />
    <file src=".\readme.md" target="docs\" />
  </files>
</package>

生成Nuget包

在当前这个.csproj目录,执行如下命令,它就会根据我们刚才.nuspec\Properties\AssemblyInfo.cs的信息结合起来,形成我们要的Nuget包。

nuget pack

image

image

最终效果有没有达到预期,我们可以用离线Nuget包源来验证下就知道了,方式后面会介绍。

image

SDK样式项目打包

获取DotNet CLI

其实这个你装了DotNet Core SDK的时候已经自带了,可以执行命令验证下:

dotnet --version

image

准备打包信息

创建一个.Net Standard的类库项目,并且添加到解决方案中:

dotnet new classlib --framework "netstandard2.0" -o netStandardLibrary
dotnet sln add .\netStandardLibrary\netStandardLibrary.csproj

image

对SDK风格的项目来说,一切都简单了,打包信息直接在.csproj文件中,默认它可以是这样子:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
  </PropertyGroup>

</Project>

接下来只需要在PropertyGroup节点中来添加打包所需的信息就是了。

<PackageId>netStandardLibrary</PackageId>
<Version>1.0.0</Version>
<Authors>Taylor</Authors>
<Company>Taylor Inc.</Company>

甚至还可以添加开关配置,这样它默认就会生成Nuget包

<PropertyGroup>
  <PackRelease>true</PackRelease>
</PropertyGroup>

生成Nuget包

同样的,还是在.csproj目录,直接执行Dotnet CLI的命令即可:

dotnet pack -c Release

image

这时候在.\bin\Release\netStandardLibrary.1.0.0.nupkg就得到这个文件了。

image

发布到Nuget.org

获取Nuget.org密钥

首先你需要准备一个微软账号,然后使用这个账号来授权登录https://www.nuget.org即可,期间会让你选一个名字注册。

然后前往账号菜单下的API Keys页面。

image

点击Create按钮创建一个新的授权密钥

image

其中Key Name随便填,但是Glob Pattern那里可以填*,代表没有限制,过期时间目前最长也就365天,然后点击Create按钮即可。

image

创建成功之后,就可以在Manage列表中看到它,这里有一个Copy按钮,点击它,并且妥善保存好这个内容。

image

这里特别注意,这个Copy只有一次机会,点击后就没得点了,所以这个操作前往别犯糊涂。

推送到Nuget.org

这里有个特别要注意的技巧,通过发布多个包的时候,会存在依赖关系,我们应该将被依赖的包先发布,再逐步发布后面的包。

推送到Nuget.org特别简单,一句命令即可:

nuget push .\xxxxxxx.xxxxxxx.xxxxxxx.x.x.x.nupkg $ApiKey -Source https://api.nuget.org/v3/index.json

将其中xxxxxxx.xxxxxxx.xxxxxxx.x.x.x.nupkg替换成自己包的名称即可,将$ApiKey替换成前面保管好的密钥。

这里如果你是要推送到自己的私有仓库,只需要把ApiKey和Source改成自己私有仓库对应的即可。

image

看到Your package was pushed.即表示发布成功。

这时候前往Nuget官网或者在Visual Studio进入Nuget包管理就可以搜到它了(新包大概需要5-6分钟建立索引)。

image

离线安装Nuget包

有时候,如果你在本地打包好了,但是不想发布到包平台,其实也可以本地离线安装,这个操作起来非常方便。

新建本地包源

打开Visual Studio顶部菜单中的工具-Nuget包管理器-程序包管理器设置进入Nuget包设置页面。

image

切换到左侧Nuget包管理器-程序包源,在右上角找到+按钮添加一个新的包源。

修改掉创建后的默认值,比如名称可以改成Local Package Source,然后点击那一行的...按钮选择放置了本地Nuget包的文件夹,最后点击更新按钮。

image

使用本地包源

接下来,前往你要添加Nuget包的项目上右键,进入管理Nuget程序包菜单,进入浏览界面,关键的一步是,切换最右侧的包源为刚才添加的本地那个。

image

这时候你就可以看到你本地的包了,你可以像平时一样安装即可。

image

不过需要注意的是,如果你安装的包如果对其他包存在依赖,那么你可能需要先安装依赖包,也许这个依赖包是公开包源的,需要先切回如Nuget.org等在线包源。

Nuget配置

配置文件位置

Nuget的行为由一个或多个Nuget配置文件(nuget.config)的累积设置驱动。

配置文件可能存在哪种位置:

  • 解决方案

在解决方案文件夹根目录或者往上到驱动器目录的任何文件夹中,只要发现了nuget.config文件就会被累积。

在解决方案层面设置一个nuget.config可以让我们的nuget配置随着解决方案一起携带,便于团队内部实现私有Nuget服务的开箱即用。

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <packageSources>
        <add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
    </packageSources>
</configuration>
  • 用户级别配置

在用户的目录位置%appdata%\NuGet\存在NuGet.Config文件,它将影响当前用户下所有项目的Nuget配置。

image

  • 计算机级别配置

在当前计算机的%ProgramFiles(x86)%\NuGet\Config存在xxxx.config文件,它将影响当前计算机下所有项目的Nuget配置。

image

Microsoft.VisualStudio.Offline.config内容如下:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <packageSources>
    <add key="Microsoft Visual Studio Offline Packages" value="C:\Program Files (x86)\Microsoft SDKs\NuGetPackages\"/>
  </packageSources>
</configuration>

Microsoft.VisualStudio.FallbackLocation.config内容如下:

<?xml version="1.0" encoding="utf-8"?>
<!--<auto-generated>
	This code was generated by a tool.
	Changes to this file may cause incorrect behavior and will be lost if
	the code is regenerated.
</autogenerated>-->
<configuration>
  <fallbackPackageFolders>
    <add key="Microsoft Visual Studio Fallback Folder" value="C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages" />
  </fallbackPackageFolders>
</configuration>

参考

posted @ 2022-08-25 11:41  TaylorShi  阅读(766)  评论(0编辑  收藏  举报