
1. 从零开始为什么NuGet是.NET开发的“水电煤”如果你刚开始接触Visual Studio进行.NET开发可能会对项目里那些“引用”感到困惑。它们从哪来怎么管理版本别人给我的项目我怎么才能快速把缺少的库都装上这些问题在NuGet出现之前是每个.NET开发者都要面对的“阵痛期”。NuGet的出现彻底改变了这一切它就像开发环境里的“水电煤”基础设施让依赖管理变得像拧开水龙头一样简单直接。简单来说NuGet是.NET平台包括.NET Framework, .NET Core, .NET 5/6/7/8的官方包管理器。你可以把它想象成一个巨大的、中心化的“零件仓库”。当你的项目需要一个功能比如解析JSON、连接数据库、或者实现一个加密算法时你不需要自己从头造轮子也不需要去某个官网下载一堆DLL文件然后手动添加引用。你只需要告诉NuGet“我需要Newtonsoft.Json这个库”它就会自动从仓库我们称之为“包源”默认是官方的nuget.org找到这个库下载它并把它正确地安装到你的项目中包括它自身可能依赖的其他库我们称之为“传递依赖”。整个过程自动化、版本化、可重现。为什么说它是“全流程”呢因为从一个空项目到一个能跑起来的项目NuGet贯穿了“发现 - 安装 - 管理 - 更新/卸载”的完整生命周期。今天我就以一个最常见的场景——在Visual Studio 2022中为一个控制台项目添加JSON处理库为例用最详细的截图和说明带你走通这个全流程。你会发现它远比你想的还要强大和便捷。2. 环境准备与项目创建一切开始之前在开始操作之前我们需要确保两件事一是有一个可用的Visual Studio二是创建一个干净的项目作为我们的“试验田”。这个过程虽然基础但里面有些小细节如果没注意到可能会给后续操作带来不必要的麻烦。2.1 确认Visual Studio与NuGet的集成状态首先你需要安装Visual Studio 2022或2019、2017等较新版本。社区版Community是免费的功能对于学习和个人开发完全足够。安装时请务必在“工作负载”选择界面勾选与你开发方向相关的选项例如“.NET桌面开发”或“ASP.NET和Web开发”。这些工作负载会自动安装NuGet客户端和必要的项目模板。安装完成后打开Visual Studio。你可以通过一个简单的方法验证NuGet是否就绪查看菜单栏。如果能看到“工具” - “NuGet包管理器”这个菜单项并且其下有“程序包管理器控制台”和“管理解决方案的NuGet程序包”等子项就说明集成是成功的。注意如果你使用的是非常老旧的VS版本如2015以前可能需要单独安装NuGet扩展。但对于VS2017及以后版本NuGet已是内置核心组件无需额外操作。2.2 创建一个纯净的控制台项目为了演示的清晰我们从一个最简单的项目类型开始。请按照以下步骤操作启动Visual Studio在启动窗口选择“创建新项目”。在项目模板搜索框中输入“控制台”选择“控制台应用”对应.NET Core/.NET 5或“控制台应用(.NET Framework)”。这里我推荐选择“控制台应用”C#因为它使用的是新的跨平台.NET SDK风格的项目文件.csproj其依赖管理方式更现代、简洁。点击“下一步”为项目命名例如“NuGetDemo”选择好项目存放的位置然后点击“创建”。几秒钟后一个最基础的“Hello World”程序就创建好了。此时如果你在解决方案资源管理器中展开项目依赖项可能会看到“框架”下有一个对Microsoft.NETCore.App或类似框架的引用。这是项目运行的基础不是我们通过NuGet安装的包。我们的目标是添加第三方功能包。这里有一个关键点项目文件.csproj的格式。新的SDK风格项目文件内容类似Project SdkMicrosoft.NET.Sdk将依赖项以PackageReference的形式直接写在项目文件里非常清晰。而旧的.NET Framework项目可能还会使用packages.config文件来管理包引用。本文的演示基于新的项目文件格式因为这是现在和未来的主流。如果你的项目是旧格式大部分操作逻辑相通只是管理界面和底层文件有些差异。3. 核心操作通过管理器界面搜索与安装依赖这是最常用、最直观的方式。Visual Studio提供了图形化的包管理器界面让你可以像在应用商店里找软件一样浏览、搜索和安装NuGet包。3.1 打开NuGet包管理器在解决方案资源管理器中右键点击你的项目“NuGetDemo”在弹出的上下文菜单中选择“管理NuGet程序包(N)...”。这个操作是针对单个项目的。如果你有多个项目想统一管理整个解决方案的包可以从菜单栏的“工具”-“NuGet包管理器”-“管理解决方案的NuGet程序包”进入。打开的窗口就是NuGet包管理器。它主要分为几个区域顶部的选项卡“浏览”、“已安装”、“更新”、搜索框、左侧的包源选择下拉框、中间的主体包列表、以及右侧的包详情和操作面板。3.2 搜索并选择合适的包假设我们要为项目添加处理JSON的能力。在.NET生态中Newtonsoft.Json又名Json.NET是历史悠久且功能强大的库而System.Text.Json是.NET Core 3.0后官方推出的高性能库。我们以搜索Newtonsoft.Json为例。在搜索框中输入“Newtonsoft.Json”。确保左上角的“包源”选择的是“nuget.org”。这是默认的官方源包含了绝大多数公开的包。公司内部可能会搭建私有源那时就需要在这里切换。敲下回车或等待自动搜索列表中很快就会显示出Newtonsoft.Json包。此时中间列表会显示包的名称、作者、简要描述以及最重要的——下载量和最新稳定版本号。下载量是一个非常重要的参考指标它通常意味着包的流行度和社区认可度。Newtonsoft.Json的下载量通常是数十亿级别这说明了它的统治地位。点击列表中的包右侧面板会显示更详细的信息包括完整的描述、版本历史、依赖项等。版本选择策略在右侧面板你可以看到一个版本下拉框。除非有特殊需求否则强烈建议选择最新的“稳定版”通常不带-preview, -beta等后缀。对于像Newtonsoft.Json这样的基础库最新稳定版已经过充分测试。如果你正在预览某个框架的新功能可能需要安装带预览标记的包但这会引入不稳定的风险。3.3 执行安装与理解安装过程选好版本后点击右侧面板大大的“安装”按钮。这时Visual Studio会开始执行一系列操作解析依赖NuGet客户端会分析Newtonsoft.Json这个包自身依赖哪些其他包传递依赖。对于Newtonsoft.Json它可能没有其他依赖或者依赖一些非常基础的运行时库。下载包从nuget.org源下载选定的包一个.nupkg文件及其所有依赖包到本地的全局包缓存目录通常在用户目录下的.nuget/packages文件夹。这样同一个包被多个项目使用时无需重复下载。安装到项目将包中的程序集DLL添加到项目的引用中并将包的元信息写入项目文件.csproj。生成操作某些包可能包含一些需要在安装、编译或运行时执行的脚本或内容文件NuGet会处理这些。安装过程中Visual Studio的输出窗口会切换到“程序包管理器”视图你可以看到详细的日志信息。安装成功后你会注意到几处变化在解决方案资源管理器中展开项目下的“依赖项”-“包”你会看到新安装的Newtonsoft.Json。打开项目文件.csproj你会看到新增了一行PackageReference IncludeNewtonsoft.Json Version13.0.3 /这行代码就是你的项目对这个包的依赖声明。请务必将此文件纳入源代码管理如Git这样你的队友在获取代码后只需执行还原操作就能自动获取相同版本的包。实操心得安装后如果代码中using Newtonsoft.Json;仍然报错可以尝试“生成”-“重新生成解决方案”。有时IDE的智能感知需要一点时间来同步。如果还不行检查输出窗口是否有错误信息常见问题包括网络问题导致下载失败或者项目目标框架与包支持的框架不兼容。4. 包管理器的进阶功能与项目文件解析安装只是第一步日常开发中我们更需要的是对已安装包的管理。NuGet包管理器的“已安装”和“更新”选项卡就是为此而生。4.1 查看、更新与卸载已安装的包点击管理器顶部的“已安装”选项卡你会看到当前项目所有通过NuGet安装的包列表。这里不仅包括你显式安装的包如Newtonsoft.Json也包括作为传递依赖被自动安装进来的包。更新包如果你看到某个包有可用的新版本右侧会显示“更新”标签你可以点击它然后在右侧面板选择新版本并点击“更新”。更新前务必谨慎特别是大版本更新如从12.x到13.x可能包含破坏性变更。好的做法是先查看该版本的发行说明Release Notes了解变更内容并在非生产分支上测试无误后再更新主分支。卸载包选中一个包右侧面板会有“卸载”按钮。点击后该包将从项目引用中移除对应的PackageReference行也会从.csproj文件中删除。但是该包的物理文件可能仍保留在本地全局缓存中以备其他项目使用。4.2 理解.csproj中的PackageReference现代.NET项目对NuGet包的管理精髓都浓缩在项目文件.csproj的PackageReference元素里。让我们深入看一下Project SdkMicrosoft.NET.Sdk PropertyGroup OutputTypeExe/OutputType TargetFrameworknet8.0/TargetFramework /PropertyGroup ItemGroup PackageReference IncludeNewtonsoft.Json Version13.0.3 / /ItemGroup /ProjectIncludeNewtonsoft.Json指定包的标识符ID必须与NuGet仓库中的完全一致。Version13.0.3指定要使用的确切版本。这里使用的是固定版本。除了固定版本你还可以使用版本范围这在某些场景下很有用但需要更谨慎的管理Version13.0.*使用13.0.x系列的最新版本允许最后一位版本号自动更新。Version[13.0.0, 14.0.0)使用大于等于13.0.0但小于14.0.0的最新版本。个人建议对于应用程序项目强烈推荐使用固定版本号。这能保证每次构建的一致性避免因依赖包自动升级到不兼容的新版本而导致的意外构建失败或运行时错误。对于类库项目在依赖其他基础库时可以考虑使用合理的版本范围但上限如14.0.0应明确以控制升级风险。4.3 管理多个项目的统一依赖解决方案级别当一个解决方案.sln中包含多个项目且它们都需要引用同一个NuGet包时比如一个公共工具库逐个项目安装和管理效率低下且容易出错。这时可以使用解决方案级别的包管理。从“工具”-“NuGet包管理器”-“管理解决方案的NuGet程序包”打开管理器。界面与项目级管理器类似但左侧会列出解决方案中的所有项目。你可以在这里搜索包然后在右侧选择要安装此包的项目可以多选再进行安装。这样就能一次性为多个项目添加相同的依赖。但请注意即使通过解决方案管理器安装每个项目的.csproj文件中依然会生成独立的PackageReference节点。它们只是被统一操作管理上仍然是独立的。这意味着你可以后来单独为某个项目更新或卸载这个包。5. 命令行与自动化程序包管理器控制台图形界面虽好但无法实现自动化。对于需要脚本化、重复性的操作或者更喜欢键盘流的开发者程序包管理器控制台Package Manager Console是更强大的工具。它是一个集成在Visual Studio中的PowerShell环境专门用于执行NuGet命令。5.1 打开与控制台基础通过“工具”-“NuGet包管理器”-“程序包管理器控制台”打开它。控制台打开后默认会连接到你在解决方案资源管理器中选择的默认项目。你可以通过控制台顶部的“默认项目”下拉列表快速切换当前操作的目标项目。控制台的核心命令是Install-Package。例如要安装Newtonsoft.Json你只需输入Install-Package Newtonsoft.Json然后回车。控制台会执行与图形界面相同的安装流程并在下方输出详细信息。你可以通过-Version参数指定版本Install-Package Newtonsoft.Json -Version 13.0.35.2 常用命令与自动化场景控制台命令的威力在于其可组合性和可脚本化。以下是一些常用命令Get-Package列出已安装的包。使用-Filter参数可以搜索如Get-Package -Filter Json。Update-Package更新包。Update-Package Newtonsoft.Json会更新到该包的最新版本。你也可以使用-Version指定要更新到的目标版本。Uninstall-Package卸载包。如Uninstall-Package Newtonsoft.Json。Get-Project显示当前项目的信息。自动化场景示例假设你接手一个旧项目它的packages.config文件里列了一堆过时的包引用。你可以写一个简单的PowerShell脚本在控制台中读取这个文件然后批量执行Update-Package命令或者将旧格式迁移到新的PackageReference格式虽然这通常有专门的迁移工具。注意事项控制台命令执行的是“当前默认项目”。在操作前务必确认下拉框里选对了项目否则可能把包装错了地方。另外一些复杂的包可能包含安装脚本这些脚本在控制台安装时也会被执行。6. 依赖还原、缓存与故障排查日常开发中我们经常从Git等版本控制系统拉取别人的代码。项目文件.csproj里记录了包依赖但包本身DLL文件并不在代码仓库里。这时就需要“还原”依赖。6.1 理解与执行包还原“还原”操作的含义是根据项目文件中的PackageReference定义从配置的包源如nuget.org或本地缓存中将所有需要的包及其依赖下载到本地并准备好供项目编译使用。在Visual Studio中有多种方式触发还原自动还原当你打开一个解决方案时VS通常会尝试自动还原包。你可以在输出窗口看到“还原”相关的信息。手动还原在解决方案资源管理器中右键点击解决方案或项目选择“还原NuGet程序包”。命令行还原如果你使用命令行如dotnet build或dotnet restore构建命令通常会先执行还原操作。dotnet restore是一个明确的还原命令。还原成功后所有需要的包都会被下载到本地的全局包缓存中并且在项目目录下的obj文件夹里会生成一个project.assets.json文件。这个文件是MSBuild用来理解项目所有依赖关系图包括传递依赖的关键文件不要手动修改它。6.2 本地包缓存与清理NuGet会将下载的包存储在本地的一个全局缓存目录中Windows通常在%userprofile%\.nuget\packages。这带来了两个好处一是同一个包被多个项目共享节省磁盘空间和下载时间二是离线状态下如果缓存中有对应版本的包项目依然可以还原和构建。但是长期开发后缓存目录可能会变得非常大包含许多不同版本、不同项目的旧包。你可以通过以下方式管理缓存查看缓存位置在命令行输入dotnet nuget locals all --list可以列出所有本地资源的位置包括全局包缓存。清理缓存如果遇到一些奇怪的包相关错误比如版本不一致可以尝试清理缓存。在命令行中运行dotnet nuget locals all --clear会清除所有本地NuGet资源包括缓存和临时文件。下次构建时会重新从远程源下载。踩坑实录我曾遇到一个诡异的问题本地编译正常但在CI/CD服务器上总是失败提示找不到某个特定版本的包。排查后发现是因为我本地缓存里有一个该版本包的“残骸”可能是不完整的下载导致本地还原时误以为成功了。清理本地和CI服务器上的缓存后问题解决。所以当遇到依赖问题时“清理缓存并重新还原”是一个值得尝试的万能步骤。6.3 常见问题与排查思路“无法找到包XXX”或“版本XXX不存在”检查包源确认包管理器或nuget.config文件中配置的包源地址是否正确特别是使用了私有源的时候。检查拼写和版本号包ID和版本号是大小写不敏感的但必须完全匹配仓库中的名称。网络问题尝试在浏览器中访问https://api.nuget.org/v3/index.json确认能连通nuget.org官方源。“与目标框架不兼容”这是最常见的问题之一。比如你的项目目标是.netstandard2.0但你想安装的包最高只支持.netstandard1.3。或者你的项目是.NET Framework 4.6.1但包只提供了.NET Standard或.NET Core的实现。解决方案在NuGet官网搜索该包查看其“依赖项”或“框架”选项卡确认它支持你的项目目标框架。如果不支持你可能需要寻找替代包或者升级/降级你的项目目标框架。依赖冲突当两个不同的包或同一个包的不同版本要求引用同一个基础包的不同版本时会发生冲突。例如包A依赖Newtonsoft.Json (12.0.0)包B依赖Newtonsoft.Json (13.0.0 14.0.0)。NuGet的解析器会尝试找到一个能满足所有要求的版本。如果找不到就会报错。排查查看错误信息明确是哪些包发生了冲突。然后你可以尝试更新所有相关的包到它们共同支持的新版本。如果可能使用PackageReference的Version属性强制指定一个兼容的版本需谨慎测试。寻找功能类似但没有此冲突的替代包。还原或安装速度慢检查网络连接。考虑配置离你更近的镜像源如国内的镜像源这需要修改nuget.config文件。对于公司内部搭建私有NuGet服务器可以极大提升内部包的下载速度。7. 超越图形界面配置nuget.config与使用私有源对于企业开发或个人高级用法仅仅使用默认的nuget.org源是不够的。你可能需要从公司内部的私有服务器获取包或者配置一些全局行为。这一切都通过nuget.config文件来控制。7.1 nuget.config文件的作用与位置nuget.config是一个XML格式的配置文件用于定义NuGet客户端的各种行为主要包括包源除了nuget.org你还可以添加公司私有源、其他公共镜像源如阿里云镜像。包还原设置如是否允许还原时使用包缓存、是否并行下载等。认证信息访问私有源时需要的API密钥或用户名密码。这个文件可以存在于多个位置优先级从高到低为当前目录项目目录或解决方案目录下的nuget.config。用户目录下的%AppData%\NuGet\NuGet.ConfigWindows或~/.nuget/NuGet.ConfigmacOS/Linux。机器全局的配置。通常团队协作时会在解决方案目录下放置一个nuget.config文件并提交到代码仓库这样所有拉取代码的成员都会自动使用相同的包源配置。7.2 添加与使用私有包源假设你公司的私有NuGet服务器地址是https://nuget.mycompany.com/v3/index.json。你可以在解决方案目录下创建一个nuget.config文件内容如下?xml version1.0 encodingutf-8? configuration packageSources !-- 清除默认源也可以不清除只是添加 -- clear / !-- 添加私有源并给一个友好名称 -- add keyMyCompany Private Source valuehttps://nuget.mycompany.com/v3/index.json / !-- 添加官方源 -- add keynuget.org valuehttps://api.nuget.org/v3/index.json / /packageSources !-- 定义包源的顺序NuGet会按此顺序查找包 -- packageSourceMapping packageSource keyMyCompany Private Source package patternMyCompany.* / !-- 公司内部的包都从这个源找 -- /packageSource packageSource keynuget.org package pattern* / !-- 其他所有包从官方源找 -- /packageSource /packageSourceMapping /configuration创建并保存此文件后重新打开Visual Studio或重新加载解决方案。此时再打开NuGet包管理器你会在“包源”下拉框中看到新添加的“MyCompany Private Source”。当你搜索以“MyCompany.”开头的包时NuGet会优先从你的私有服务器查找搜索其他公共包如Newtonsoft.Json时则会回退到nuget.org。实操心得配置包源映射packageSourceMapping是.NET 6/VS2022引入的一个很棒的特性。它能精确控制哪个包从哪个源获取避免了因源优先级问题导致的包下载错误比如不小心从公共源下载了与内部包同名的旧版本。对于企业开发环境强烈建议配置。7.3 处理私有源的认证如果私有源需要认证你需要在nuget.config中配置凭据。注意不建议将明文密码直接写在配置文件中。更安全的做法是使用NuGet的dotnet nuget add source命令配合--store-password-in-clear-text仅Windows且使用Windows凭据管理器或配置环境变量、使用CI/CD系统的安全变量等方式。例如通过命令行添加带用户名密码的源dotnet nuget add source https://nuget.mycompany.com/v3/index.json -n Private Source -u username -p password --store-password-in-clear-text在Windows上密码可能会被存储到Windows凭据管理器中而不是配置文件中这样更安全。8. 从依赖管理到持续集成让流程更健壮将NuGet集成到你的团队开发和持续集成/持续部署CI/CD流程中能进一步提升效率和可靠性。核心思想是保证在任何地方、任何时间基于同一份代码包括.csproj文件都能还原出完全一致的依赖环境。8.1 锁定依赖版本与启用还原锁定模式即使你在.csproj中使用了固定版本号传递依赖的包可能仍然使用了版本范围。为了达到绝对的还原一致性你可以启用“还原锁定模式”。在项目文件.csproj中添加以下属性PropertyGroup RestorePackagesWithLockFiletrue/RestorePackagesWithLockFile /PropertyGroup当你第一次运行dotnet restore或从VS执行还原后会在项目根目录生成一个packages.lock.json文件。这个文件记录了当前还原操作解析出的所有依赖包的确切版本树包括所有传递依赖。关键点将这个packages.lock.json文件提交到源代码仓库。这样CI服务器或其他开发者在还原时只要存在这个锁文件NuGet就会严格安装锁文件中记录的版本忽略任何版本范围从而实现完全一致的还原。你还可以通过--locked-mode参数在还原时强制使用锁文件dotnet restore --locked-mode如果锁文件中的版本与当前源中可用的版本不匹配例如某个包被从源中删除还原将会失败这能及早发现问题。8.2 在CI/CD流水线中配置NuGet还原在Azure DevOps、GitHub Actions、Jenkins等CI/CD工具中配置NuGet还原通常是第一步。以GitHub Actions为例一个典型的.NET构建步骤会包括jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkoutv3 - name: Setup .NET uses: actions/setup-dotnetv3 with: dotnet-version: 8.0.x - name: Restore dependencies run: dotnet restore --locked-mode # 使用锁定模式还原 - name: Build run: dotnet build --no-restore --configuration Release # 构建时不再还原注意--no-restore参数的使用因为在单独的dotnet restore步骤中已经完成了依赖还原构建步骤就可以跳过还原加快构建速度。8.3 搭建内部包仓库与包发布当团队开发出可复用的公共组件或工具库时可以将其打包成NuGet包发布到内部私有源供其他项目使用。创建NuGet包在类库项目的.csproj文件中配置包属性如PackageId,Version,Authors,Description等然后使用dotnet pack命令生成.nupkg文件。搭建私有源可以选择简单的文件共享源一个网络共享文件夹也可以使用专业的NuGet服务器软件如BaGet开源、轻量、JFrog Artifactory、Sonatype Nexus或Azure Artifacts。文件共享源最简单只需在nuget.config中添加一个指向共享文件夹路径的源即可。推送包使用dotnet nuget push命令或nuget push命令将生成的.nupkg文件推送到你的私有源。例如推送到一个文件共享源dotnet nuget push .\MyCompany.Utilities.1.0.0.nupkg --source \\server\share\NuGetPackages\建立起内部包生态系统能极大促进代码复用和团队协作的规范化。