精通-VS2022-全-
精通 VS2022(全)
原文:
zh.annas-archive.org/md5/e76b7b319f979271dfaf0be541971383译者:飞龙
前言
Visual Studio 是专业应用程序开发的必备工具,尤其是在使用 C# 和 .NET 进行开发时。它为开发者提供了一套全面的特性,简化了创建、测试和部署强大应用程序的过程。本书旨在指导开发者充分利用 Visual Studio 的高级功能。
在这本书中,我们将重点关注现代软件开发四个关键方面:
-
核心开发技能,如测试、优化、调试和重构,这对于编写干净和高效的代码至关重要
-
高级开发技术,包括跨平台应用开发、网络工具、机器学习集成和云服务,使您能够进一步扩展您的开发能力
-
DevOps 实践,通过使用 Visual Studio 内置的高级 Git 工作流程工具、GitHub Actions 的持续集成和 Azure DevOps 的有效团队合作来简化协作开发
-
定制和增强,让您能够通过创建自己的模板、扩展和强大的 NuGet 包来定制 Visual Studio 以适应您独特的流程
本书借鉴了我多年软件开发的经验,以及掌握 Visual Studio 最先进功能的领域领先专业人士的见解。随着 Visual Studio 的不断发展,开发者将越来越依赖其工具进行高效和可扩展的开发。成功的关键不仅在于编写代码,还在于通过 Visual Studio 的强大功能掌握整个开发生命周期,从设计到部署。
通过掌握这些技术,您将充分准备应对现代应用程序开发的挑战,提高您的生产力,并轻松交付专业级的应用程序。
本书面向的对象
这本书是为那些希望提升他们在 Visual Studio 和 C#/.NET 应用程序开发领域专业知识的开发者、团队领导和 IT 专业人士所设计的。以下群体将从这个内容中受益最大:
-
专业开发者:寻求提升他们对 Visual Studio 高级功能知识并提高他们在测试、优化、调试和 DevOps 集成等领域的技能的开发者。本书将帮助他们构建更高效、可扩展和专业的应用程序。
-
开发团队领导:寻求利用 Visual Studio 的强大工具来优化工作流程、实施有效的 DevOps 实践并增强团队内部协作的团队领导者。本书将帮助他们更高效地管理多平台和基于云的项目。
-
IT 和 DevOps 专业人士:负责管理开发环境、自动化部署管道或支持开发团队的人将获得关于高级 Git 工作流程、持续集成和 Docker 容器化的宝贵见解。本书提供了优化 Visual Studio 以实现团队协作和项目成功的实用指南。
无论你专注于编码、管理开发团队还是处理 DevOps 任务,这本书都提供了掌握使用 Visual Studio 进行专业应用程序开发的工具和知识。
本书涵盖的内容
第一章 ,单元测试和测试驱动开发,介绍了单元测试和 TDD 原则的重要性。它涵盖了如何使用 Visual Studio 编写有效的单元测试,并将测试无缝集成到你的开发工作流程中。
第二章 ,高级调试策略,探讨了超出基础的调试技术。你将学习如何利用 Visual Studio 的高级调试工具来识别、隔离和解决代码中的复杂问题。
第三章 ,高级代码分析和重构,专注于分析和重构代码以提高质量和可维护性。本章涵盖了识别代码异味并增强代码结构的工具和方法。
第四章 ,性能优化和性能分析,教你如何使用 Visual Studio 的性能分析工具分析性能瓶颈并优化应用程序的速度、内存使用和效率。
第五章 ,多平台应用 UI 开发,深入探讨了构建响应式、跨平台应用程序的方法。你将学习如何使用 Visual Studio 开发在不同设备和平台上运行流畅的用户界面。
第六章 ,高级 Web 开发工具,介绍了 Visual Studio 的高级功能,用于构建现代 Web 应用程序。本章涵盖了使可扩展、高性能 Web 开发成为可能的工具和框架。
第七章 ,机器学习集成,探讨了如何将机器学习模型集成到你的应用程序中。你将学习如何利用 Visual Studio 开发由机器学习驱动的智能应用程序。
第八章 ,高级云集成和服务,专注于将云服务集成到你的应用程序中。你将探索通过 Visual Studio 提供的用于可扩展云应用程序的高级云工具和服务。
第九章 ,处理高级 Git 工作流程,介绍了高级 Git 概念和工作流程。你将学习如何管理复杂的 Git 操作,并使用 Visual Studio 的集成 Git 工具有效地协作。
第十章 ,使用 GitHub Actions 进行持续集成,涵盖了使用 GitHub Actions 设置持续集成管道。本章解释了如何直接从 Visual Studio 自动化测试和部署流程。
第十一章 ,使用 Azure DevOps 进行协作开发,探讨了如何使用 Azure DevOps 管理协作项目。您将学习如何将 Azure DevOps 与 Visual Studio 集成以简化团队协作和项目管理。
第十二章 ,Visual Studio Docker 容器工具,教您如何使用 Visual Studio 内置的容器工具开发、测试和部署使用 Docker 的应用程序。本章涵盖了容器化的最佳实践和工作流程。
第十三章 ,编写您自己的项目模板,介绍了如何在 Visual Studio 中创建自定义项目模板以简化开发工作流程。您将学习如何调整模板以满足您项目的特定需求。
第十四章 ,编写您自己的 Visual Studio 扩展,解释了如何开发 Visual Studio 扩展以增强您的开发环境。本章提供了逐步指导,以构建和发布您自己的扩展。
第十五章 ,为社区创建和发布强大的 NuGet 包,专注于创建可重用、可共享的 NuGet 包。您将学习如何打包和发布您的代码到社区或企业,以简化其他开发者的开发流程。
为了充分利用本书
您应该对 C#和.NET 平台有基本的了解。某些部分可能引用云订阅层级,但订阅不是阅读本书大部分内容所必需的。
| 本书涵盖的软件/硬件 | 操作系统要求 |
|---|---|
| Visual Studio | Windows |
| . NET | |
| C# | |
| Amazon Web 服务 ( AWS ) | |
| Azure | |
| Google Cloud 平台 ( GCP ) |
由于 Visual Studio 发展迅速,我建议您使用 IDE 的最新预览版以获得最佳体验并尝试最新的功能。
如果您使用的是本书的数字版,我们建议您亲自输入代码或从本书的 GitHub 仓库(下一节中提供链接)获取代码。这样做将帮助您避免与代码的复制和粘贴相关的任何潜在错误。
下载示例代码文件
您可以从 GitHub 下载本书的示例代码文件:github.com/PacktPublishing/Mastering-Visual-Studio-2022。如果代码有更新,它将在 GitHub 仓库中更新。
我们还有其他来自我们丰富的书籍和视频目录的代码包,可在github.com/PacktPublishing/找到。查看它们!
使用的约定
本书使用了多种文本约定。
文本中的代码:表示文本中的代码单词、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟 URL、用户输入和 Twitter 昵称。以下是一个示例:“使用nuget push命令或集成到您的 CI/CD 管道中来自动化此过程。”
代码块设置如下:
<PropertyGroup>
<TargetFrameworks>net46;netstandard2.0</TargetFrameworks>
</PropertyGroup>
任何命令行输入或输出都按以下方式编写:
git add Car.cs
粗体:表示新术语、重要单词或您在屏幕上看到的单词。例如,菜单或对话框中的单词以粗体显示。以下是一个示例:“在解决方案资源管理器中右键单击项目。”
小贴士或重要注意事项
看起来像这样。
联系我们
我们读者的反馈总是受欢迎的。
一般反馈:如果您对本书的任何方面有疑问,请通过 customercare@packtpub.com 给我们发邮件,并在邮件主题中提及书名。
勘误表:尽管我们已经尽一切努力确保内容的准确性,但错误仍然可能发生。如果您在此书中发现错误,我们将不胜感激,如果您能向我们报告此错误。请访问www.packtpub.com/support/errata并填写表格。
盗版:如果您在互联网上以任何形式发现我们作品的非法副本,如果您能提供位置地址或网站名称,我们将不胜感激。请通过版权@packt.com 与我们联系,并提供材料的链接。
如果您有兴趣成为作者:如果您在某个领域有专业知识,并且您有兴趣撰写或为书籍做出贡献,请访问authors.packtpub.com。
分享您的想法
一旦您阅读了《精通 Visual Studio 2022》,我们很乐意听到您的想法!请点击此处直接转到此书的 Amazon 评论页面并分享您的反馈。
您的评论对我们和科技社区都很重要,并将帮助我们确保我们提供高质量的内容。
下载此书的免费 PDF 副本
感谢您购买此书!
您喜欢在路上阅读,但又无法携带您的印刷书籍到处走?
您的电子书购买是否与您选择的设备不兼容?
别担心,现在,随着每本 Packt 书籍,您都可以免费获得该书的 DRM 免费 PDF 版本。
在任何地方、任何地方、任何设备上阅读。直接从您最喜欢的技术书籍中搜索、复制和粘贴代码到您的应用程序中。
优惠不会就此结束,您还可以获得独家折扣、时事通讯和每日免费内容的每日电子邮件。
按照以下简单步骤获取好处:
- 扫描二维码或访问以下链接

packt.link/free-ebook/978-1-83588-468-3
-
提交您的购买证明
-
就这些!我们将直接将您的免费 PDF 和其他优惠发送到您的邮箱
第一部分:掌握核心开发技能
在本第一部分中,我们探讨了提升您的软件开发实践到专业水平所需的必备技能。通过分解核心开发技能,包括测试、优化、调试和重构,这些领域的每一个都将提高您编写更干净、更高效代码的能力,并自信地应对复杂挑战,最终得益于 Visual Studio 的强大功能和工具,提高您整体的开发流程。
本部分包含以下章节:
-
第一章 ,单元测试和测试驱动开发
-
第二章 ,高级调试策略
-
第三章 ,高级代码分析和重构
-
第四章 ,性能优化和性能分析
第一章:单元测试和测试驱动开发
本章深入探讨了 Visual Studio 2022 中单元测试和 测试驱动开发(TDD)的基础概念。您将了解在编写代码之前编写测试的重要性,并探索测试框架的集成。实际示例将指导您创建有效的单元测试,确保代码可靠性,并培养测试驱动的心态。
我们将开始一段旅程,了解单元测试和 TDD 的基本要素。我们将从对这些基础概念的整体了解和探索它们在软件开发生命周期中的重要性开始。
在此介绍之后,我们将深入探讨在 Visual Studio Code 中设置单元测试的实际方面。本节将指导您完成配置开发环境的初始步骤,为将测试框架集成到您的流程中打下基础。
一旦设置完成,我们将过渡到创建第一个测试,使用的是 Visual Studio 的一个功能——IntelliTest,它可以自动化生成单元测试。这种动手经验将展示 IntelliTest 如何简化测试过程,使其更加高效和节省时间。
接下来,我们将应用所学知识,通过一个真实世界示例练习从零开始的 TDD。本节将向您介绍在编写代码之前编写测试的过程,这是 TDD 的一个核心原则,以及它如何导致更健壮和可靠的软件。
最后,我们将探索如何使用 Live Unit Testing 自动化测试过程,这是一个在您编码时在后台运行单元测试的功能。本节将向您展示如何启用并利用 Live Unit Testing 来增强您的开发流程,确保您的代码在整个开发过程中保持可靠且无错误。
在本章中,我们将涵盖以下主要主题:
-
介绍单元测试和 TDD
-
在 Visual Studio 中设置单元测试
-
使用 IntelliTest 创建测试
-
使用真实世界示例练习 TDD
-
使用 Live Unit Test 自动化测试
技术要求
在编写本章时,我使用了以下版本的 Visual Studio:
-
Visual Studio Enterprise 2022 版本 17.12.0
-
预览 1.0
本章的代码文件可以在github.com/PacktPublishing/Mastering-Visual-Studio-2022/tree/main/ch01找到
介绍单元测试和 TDD
在深入探讨通过 Visual Studio 使用单元测试和 TDD 方法之前,让我们先回顾一下它们是什么以及为什么在项目中考虑它们是有价值的。
单元测试是一种针对软件系统内单个单元或组件的集中式软件测试方法。单元测试的主要目标是确保每个软件单元按预期工作,满足指定的要求。通常由开发者执行,单元测试在开发早期进行,先于整个系统的集成和测试。
自动化单元测试在代码发生修改时执行,确保新更改不会破坏现有功能。这些测试被精心设计来验证最小的可想象代码单元,如函数或方法,在更广泛的系统之外进行。这种方法使开发者能够在开发初期迅速识别和解决问题,从而提高整体软件质量并减少后续测试阶段所需的时间。
单元测试的 F.I.R.S.T.原则
通过认真遵循单元测试的快速、隔离/独立、可重复、自我验证、及时(F.I.R.S.T.)原则,开发者被引导精心制作有效的测试。这些原则作为指南针,通过灌输支撑单元测试可靠性和鲁棒性的关键标准,将测试过程引导至卓越。
让我们更详细地看看 F.I.R.S.T.的每个因素:
-
快速:执行速度是有效单元测试的一个基本特征。单元测试必须运行迅速,因为开发者经常在整个开发过程中执行它们。快速的测试套件提供快速反馈,使开发者能够及时识别和纠正问题。这不仅加速了开发周期,还培养了一种响应性文化,鼓励开发者频繁运行测试。快速获得反馈的能力增强了早期发现潜在问题的能力,促进了对软件质量的主动方法。
-
隔离/独立:独立性是单元测试的一个基石原则。每个单元测试都应该在隔离状态下运行,不依赖于其他测试。测试执行的顺序或某个测试的成功或失败不应影响其他测试的结果。这种隔离确保开发者能够以专注的方式定位和解决问题,简化调试过程。遵循独立性的原则,开发者能够精确地识别问题的根源,从而加速问题的解决过程。
-
可重复性:单元测试的可重复性对于维护测试过程的一致性至关重要。单元测试应在每次执行时始终产生相同的结果。这种一致性确保了测试结果的可信度,促进了一个可靠和可预测的测试环境。如果测试失败,开发者应该能够一致地重现失败,使他们能够自信地调查和解决问题。可重复性是建立对测试套件和整体软件开发过程信任的基础。
-
自我验证:单元测试应具备成功或失败的自包含标准,无需人工解释。自我验证的测试确保结果明确,减少了误解的可能性。开发者可以仅根据测试结果快速了解代码的状态,从而简化调试和问题解决过程。单元测试的自我验证特性有助于测试套件的清晰性和有效性,使开发者能够根据每个测试的明确结果做出明智的决策。
-
及时性:测试编写的及时性是单元测试有效性的关键因素。理想情况下,测试应该在相应的代码实现之前编写。这种主动的方法确保测试作为期望行为的活生生的规范,指导实现过程。及时编写测试为定义明确和受控的开发周期奠定了基础。及时测试在开发周期早期识别和解决问题上也发挥着关键作用,减少了缺陷传播到软件开发后期阶段的可能性。采用及时测试可以增强整个软件开发生命周期的效率和可靠性。
现在我们已经建立了单元测试及其原则的基础理解,让我们将注意力转向 TDD 的更广泛背景。
TDD – 软件质量统一原则
这些 F.I.R.S.T 原则无缝地铺平了通往一个称为 TDD 的总体方法的道路。TDD 将设计、开发和测试合并到一个统一的框架中,为开发者提供了一种全面的方法,不仅能够编写简单和干净的代码,还能确保彻底的测试。增量开发方法系统地测试了业务逻辑的所有方面,使 TDD 成为创建高质量软件的黄金标准。它在整个过程中体现了最佳的编码和设计实践。
TDD 的主要目的是实现更简单、更可靠的代码。为此,TDD 遵循一个简单而有效的过程,即红-绿-重构周期:

图 1.1 – TDD 周期
让我们更详细地了解这个 TDD 周期:
-
红色 – 编写一个 失败的测试 :
在 TDD 的第一个阶段,称为红阶段,开发者通过创建一个失败的测试来开始他们的旅程。这个测试专门针对尚未实现的小功能单元。它作为期望行为的具体表达,本质上概述了尚未编写的代码的期望。重要的是要注意,在这个阶段,测试预计会失败,因为相应的功能尚未存在于代码库中。
红阶段的主要目的是为后续的开发过程设定一个明确的目标。通过最初专注于预期结果而不放置任何代码,开发者为即将实施的功能制定了路线图。在编写代码之前先编写测试的这种有意行为不仅为即将到来的功能建立了规范,还有助于巩固开发者对当前问题的理解。
-
绿色 – 编写通过测试所需的最小代码:
在红阶段之后,开发过程进入绿色阶段。在这里,开发者编写必要的最小代码,使之前编写的测试成功通过。这个阶段的重点是简洁和效率。目标是不要创建复杂的解决方案,而是解决失败测试所突出的即时需求。
通过专注于实现成功所需的最小代码量,开发者培养了一种简洁的文化,避免了不必要的复杂性。这种专注的方法鼓励创建满足测试具体需求的代码,为既功能性强又简洁的解决方案奠定基础。在这个阶段测试的成功表明了目标功能的实现,验证了在红阶段设定的初始期望。
-
重构 – 重构代码:
在测试通过后,开发过程进入重构阶段。在这个阶段,开发者会退后一步,回顾并增强已经实现的代码。重构的主要目标是在不改变其功能的前提下,提高代码的可维护性、可读性和可扩展性。
重构是 TDD 的关键方面,因为它确保代码库保持清洁并适应未来的变化。开发者努力消除冗余,改进命名约定,并在适当的地方应用设计模式。这个阶段强化了生产不仅功能性强而且精心制作的代码的承诺。这个阶段的成功完成为长期有效的代码库奠定了基础。
-
重复 – 迭代过程:
TDD 遵循迭代方法,重复(Repeat)阶段封装了这种开发方法的循环性质。对于需要实现的新功能,整个红-绿-重构(Red-Green-Refactor)周期都会重复进行。这种迭代过程确保代码库的系统性和渐进式演变,每个周期都对软件的整体开发做出贡献。
通过重复循环,开发者不断改进和扩展应用程序,响应不断变化的需求,并确保代码与项目目标保持一致。TDD 的这种迭代性质促进了适应性和敏捷性,使其成为具有变化或发展需求的项目的一种有价值的开发方法。
这种方法不仅确保创建出功能软件,而且培养了在开发过程中的持续改进和适应性思维模式。
AAA 模式 - 测试的结构化方法
建立在 TDD 和 F.I.R.S.T 原则的基础上,单元测试领域中的另一个关键方法是安排-行动-断言(AAA)模式。该模式为测试套件内的测试组织提供了一个统一的结构。AAA 模式对测试套件的可读性和可维护性做出了重大贡献,与 TDD 的总体目标无缝对接。
AAA 模式将测试分解为三个不同的部分:
-
安排:本节涉及设置测试环境。
在安排(Arrange)部分,重点是准备测试环境。这包括设置要测试的对象,将系统单元(SUT)带到特定状态,并配置任何依赖项。无论是直接实例化对象还是准备测试替身依赖项,目标都是为测试建立一个受控和一致的开始点。
-
行动:本节涉及在系统单元(SUT)上执行操作。
行动(Act)部分是实际与系统单元(SUT)交互的地方。这包括在系统单元上调用方法或执行操作,传递任何必需的依赖项,并在适用的情况下捕获输出值。行动阶段对于模拟系统的实际使用和观察其行为至关重要。
-
断言:本节专注于验证预期的结果。
在断言(Assert)部分,测试对预期的结果做出明确声明。这可能包括检查返回值、检查系统单元及其协作者的最终状态,或验证调用在它们上的方法。断言阶段是测试的总结,确保行为与预期结果一致。
AAA 模式的结构化方法为套件中所有测试提供了清晰和一致性。通过遵循此模式,开发者可以轻松理解并导航测试,从而降低整个测试套件的维护成本。无论从 Arrange、Act 还是 Assert 开始,AAA 模式都能适应不同的测试风格,同时促进统一和系统的测试方法。
现在,我们已经对单元测试和 TDD 进行了简要的介绍,让我们深入探讨如何在 Visual Studio 中创建单元测试项目。
在 Visual Studio 2022 中设置单元测试
在本节中,我们将首先在 Visual Studio 中创建一个单元测试项目。一旦完成,我们将概述测试资源管理器视图及其主要选项。测试资源管理器视图充当 IDE 中所有测试活动的中心枢纽,提供对我们测试套件状态和性能的全面概述。它允许我们轻松导航测试结果,识别失败,并访问每个测试用例的详细信息。
创建单元测试项目
Visual Studio 和 .NET 支持三种测试框架:
-
MSTest:这是 Microsoft 为 .NET 应用提供的默认测试框架。它完全集成到 Visual Studio 中,并提供在 IDE 中编写和运行测试的功能。
-
NUnit:这是 .NET 应用中流行的开源测试框架。它提供了一个灵活且可扩展的平台来编写和执行测试,并在 .NET 社区中得到广泛应用。
-
xUnit:这是另一个用于 .NET 应用的开源测试框架。与 MSTest 和 NUnit 相比,它采用更现代和灵活的方法,并且在 .NET 开发者中越来越受欢迎。
首先,你需要为你的测试集创建一个新的项目,在包含我们想要测试的项目解决方案中。右键单击你的解决方案,然后选择添加 | 新建项目...。这将带您进入以下屏幕:

图 1.2 – 添加新的测试项目
我通过三个顶部下拉菜单过滤了这个视图,以保持默认显示在 Visual Studio 中可用的测试模板项目。你可能注意到列表中的最后两个模板提到了Playwright。Playwright 是一个库,它使现代 Web 应用能够进行端到端测试。使用它,你可以创建单元测试来评估用户界面的功能。
由于 xUnit 是行业中最常用的框架,我们将专注于它来展示我们的示例。
创建单元测试项目的另一种方法是直接在代码库中右键单击你的类,然后从菜单中选择创建单元测试:

图 1.3 – 从菜单中选择创建单元测试
此操作将打开一个菜单,允许您配置您的单元测试项目:

图 1.4 – 创建单元测试窗口
默认情况下,这允许您创建一个 MSTestv2 项目,但您可以安装额外的扩展来使用其他框架。如果您已经创建了一个单元测试项目,您可以将测试方法添加到其中。
无论您如何创建它们,本项目中所有测试都可以在测试探索器视图中进行管理,我们将在下一节中探讨它。
测试探索器视图概述
测试探索器在 Visual Studio 2022 中作为强大的集中式工具,简化了单元测试的管理和执行。这个功能丰富的窗口允许开发者无缝地查看、组织和运行他们的单元测试,在集成开发环境(IDE)中。
要访问测试探索器,有两种选择:
-
您可以在 Visual Studio 中导航到测试菜单,或利用通过按下Ctrl + E,释放它们,然后按下T键可访问的方便的键盘快捷键。
-
自 17.6 版本以来,您可以使用一站式搜索功能快速访问 Visual Studio 提供的所有功能。只需使用Ctrl + Q快捷键打开一站式搜索,输入测试探索器,然后按Enter键,您将被导向测试探索器窗口。
这是测试探索器窗口的视觉展示:

图 1.5 – 测试探索器窗口
测试探索器控制台提供了所有可用测试的清晰和组织视图,使得开发者能够轻松地浏览他们的测试套件。此界面提供了测试管理的先进功能,例如以下内容:
- 分类和分组测试:利用属性和类别根据功能区域、功能或特定要求对测试进行分组。这有助于创建逻辑层次结构,并使关注特定测试子集变得更容易。默认情况下,测试基于项目分组,然后是命名空间,接着是类。如果您想修改测试的组织结构,只需在测试探索器中点击按组按钮并选择一个新的分组标准:

图 1.6 – 测试探索器 – 按组
这里是您可以选择的分组描述:
-
持续时间:按执行时间分组:快速、中等和慢速
-
状态:按执行结果分组测试:失败的测试、跳过的测试、通过的测试和未运行的测试
-
目标框架:按项目目标框架分组测试
-
命名空间:按包含的命名空间分组测试
-
项目:按包含的项目分组测试
-
类:按包含的类分组测试
-
过滤和搜索:在大型代码库中,定位特定测试可能具有挑战性。测试资源管理器提供过滤选项和强大的搜索功能。

图 1.7 – 测试资源管理器 – 应用搜索过滤器
您可以在文本框中输入命令,例如 命名空间:"" 或您希望用于搜索的任何其他过滤标准。此外,您可以直接点击提供的命令来启动过滤。
- 创建播放列表:您可以在 Visual Studio 中创建和管理测试播放列表,以组织和运行特定的测试集。要创建播放列表,请在测试资源管理器中选择一个或多个测试,右键单击,然后选择 添加到播放列表 | 新建播放列表。

图 1.8 – 测试资源管理器 – 添加到播放列表
播放列表在新 测试资源管理器 选项卡中打开,您可以为其命名并指定位置。您可以通过添加或删除测试来编辑播放列表,并可以使用 编辑 按钮通过复选框更方便地管理测试。播放列表可以是动态的,并基于包含或排除的测试自动更新。它们可以保存为 XML 文件,如果需要可以手动编辑。
现在我们已经对 测试资源管理器 视图有了概述,让我们探索 Visual Studio 2022 的预览功能并使用它创建一个测试。
使用 IntelliTest 创建测试
在本节中,我们的目标是探索如何使用 IntelliTest 创建测试。为此,我们首先将学习如何启用 IntelliTest 功能。接下来,我们将学习如何执行它并使用它生成测试。在本节结束时,我们将学习如何通过保存、执行和审查来组织我们生成的单元测试。
IntelliTest 提供特征测试,允许您通过一系列传统的单元测试来了解代码的行为。这个套件可以作为回归测试套件,帮助处理重构旧代码或未知代码的挑战。
通过引导测试输入生成,IntelliTest 采用开放代码分析和约束求解方法自动生成精确的测试输入值,通常无需用户干预。它为复杂对象类型生成工厂,并允许自定义这些工厂以满足特定要求。代码中指定的正确性断言被用于进一步指导测试输入生成。
与 Visual Studio IDE 无缝集成,IntelliTest 为测试套件生成提供了一个统一的环境。在测试套件创建过程中收集的信息,包括自动生成的输入、代码输出和生成的测试用例,以及它们的通过或失败状态,在 Visual Studio 中均可轻松访问。这种集成使得在 IDE 中无需离开即可轻松地在代码精炼和 IntelliTest 重新运行之间迭代。测试结果可以保存为解决方案中的单元测试项目,并由 Visual Studio 测试资源管理器自动识别。
IntelliTest 可在 Visual Studio Enterprise Edition 中使用。它系统地探索代码库,为每个方法生成测试数据和单元测试,以确保全面的代码覆盖并验证代码行为。截至编写本文时,IntelliTest 是 Visual Studio 17.9 的预览功能,因此您必须通过以下步骤从 选项 菜单中启用它:
-
前往 工具 | 选项 | 管理 预览功能 。
-
在 预览功能 下检查 IntelliTest 支持 NetFx 和 Net6 使用 Z3 v4 选项。

图 1.9 – 启用预览功能 – Intellitest
启用后,我们可以探索 IntelliTest 的工作方式。例如,我创建了一个实现 FizzBuzz 的公共类。要为该类使用 IntelliTest 生成测试,右键单击类名,找到 IntelliTest (预览) 选项,然后选择 生成测试:

图 1.10 – IntelliTest – 生成测试
IntelliTest 执行和测试生成
IntelliTest 使用各种输入多次执行我们的代码。每次执行都在表中记录,显示输入测试数据以及相应的输出或发生的任何异常。

图 1.11 – 使用 IntelliTest 生成测试
在测试生成后,我们可以访问测试项目并检查已生成的参数化单元测试。
保存、执行和审查单元测试
我们可以选择我们想要保留并使用的单元测试,并使用保存选项来保存它们。

图 1.12 – IntelliTest 的保存选项
窗口左上角的复选框允许您过滤通过类的所有方法。与每一行相关联的单独单元测试存储在测试项目中的 .g.cs 文件中,而参数化单元测试存储在其各自的 . cs 文件中。

图 1.13 – IntelliTest – 单元测试项目
我们可以使用测试资源管理器执行这些单元测试并审查结果,就像我们处理手动创建的单元测试一样。
与经典单元测试类似,我们可以通过选择菜单中的选项来生成项目,而无需首先运行 IntelliTest。
使用 IntelliTest 从您的代码库中生成测试是一个非常有价值的工具,特别是对于遗留项目和回归测试。现在,让我们通过一个真实世界的例子来说明如何在 Visual Studio 中实现 TDD。
通过真实世界的例子练习 TDD
在 TDD 中,一切从规格说明和对预期功能的彻底理解开始。为了编写有效的测试,理解我们想要完成的意义是至关重要的。考虑到这一点,让我们为我们的示例建立一个场景。
我们将创建一个ValidateMail方法来处理电子邮件验证。我们的目标是探索 Visual Studio 中可用的工具,以增强我们的 TDD(测试驱动开发)体验。
现在我们已经概述了我们的需求,我们的下一步是开始创建我们的单元测试项目。为此,我们将选择 xUnit,正如本章前面所讨论的。我们将创建一个空的类库项目:
-
我们将首先在 xUnit 项目中编写一个测试,指定我们想要实现的行为或功能:
[Fact] public void ValidateMail_NewUser_ReturnsTrue() { // Arrange var user = new User(); // Act bool result = user.ValidateMail("john@example.com"); // Assert Assert.True(result); } -
当我们编写这段代码时,我们首先会注意到我们的测试无法编译,因为我们的类库项目中还没有User类。
-
我们将利用 IntelliSense 的强大功能来创建我们的类及其方法。IntelliSense 是 Visual Studio 中集成的代码补全工具,提供各种功能,如列出成员、参数信息、快速信息和完成单词。这些功能有助于更深入地理解正在使用的代码,帮助管理键入参数,并允许通过最少的按键快速添加对属性和方法的调用。
-
将光标放在User()类上,展开 IntelliSense 菜单,选择生成新类型…快速操作:

图 1.14 – 生成新类型...
- 这将打开一个窗口,我们可以选择可访问性(默认、内部或公共)、类型(类或结构)、项目,以及是否创建新文件或使用现有文件。由于我们选择了我们的类库项目,我们新类的可访问性显然设置为公共。

图 1.15 – 生成类型窗口
- 现在,以同样的方式,我们将使用 IntelliSense 来创建我们的ValidateMail()方法:

图 1.16 – 生成方法 ValidateMail’
- 完成这些后,我们的测试已经构建,但它仍然失败,因为我们还没有修复其行为。
这是我们的User类,包含使测试通过所需的最少代码:
public class User
{
public User()
{
}
public bool ValidateMail(string mail)
{
return true;
}
}
现在我们有一个返回true的ValidateMail方法,它应该遵守我们的测试规格说明。
您可以使用位于方法上方的高级访问功能来运行单元测试,而无需进入测试资源管理器视图。

图 1.17 – 使用快速访问工具运行测试
到这里了;我们的第一个测试是绿色的。我们可以编写第二个测试类,该类将处理我们的ValidateMail()必须返回false的情况。为此,我们将使用Theory和InlineData xUnit 属性:
[Theory]
[InlineData("invalidemail")]
[InlineData("invalidemail@")]
[InlineData("invalidemail@example")]
[InlineData("invalidemail@example.")]
[InlineData("invalidemail@.com")]
public void ValidateMail_InvalidEmail_ReturnsFalse(string email)
{
// Arrange
var userManager = new User();
// Act
bool result = userManager.ValidateMail(email);
// Assert
Assert.False(result);
}
我们准备进行另一轮迭代,从红色变为绿色。以下是使单元测试通过所需的最少代码的方法:
public bool ValidateMail(string email)
{
if (!email.Contains('@'))
return false;
if (email.EndsWith('@'))
return false;
if (!email.Contains('.'))
return false;
if (email.EndsWith('.'))
return false;
if (email.Contains("@."))
return false;
return true;
}
在这里,我们正在检查测试方法的每个条件,每个测试都有一个If来使其通过。
如您所见,我们的方法保持了一种天真而简单的视角。现在,是时候进入我们 TDD 流程的重构阶段了。为此,我们将探索 Visual Studio 的一个名为实时单元测试的功能。
使用实时单元测试自动化测试
在本节中,我们将探索使用实时单元测试自动化测试的功能。首先,我们将学习如何配置实时单元测试。然后,我们将看到如何启动它
实时单元测试通过在您进行代码更改时自动执行单元测试来革新测试过程。这个动态功能为开发者提供了重构和修改代码的信心。通过在代码编辑期间自动运行所有受影响的测试,实时单元测试确保所做的任何更改都不会引入回归。
此外,实时单元测试可以提供有关代码库测试覆盖率充分性的见解。它实时地以可视化的方式呈现代码覆盖率,使开发者能够快速识别测试不足的区域。
通过导航到测试 | 实时单元测试 | 启动来激活此功能。

图 1.18 – 开始实时单元测试
当您首次启动实时单元测试时,配置窗口将打开:

图 1.19 – 配置实时单元测试
配置实时单元测试
当实时单元测试被禁用时,您可以通过导航到测试 | 实时单元测试 | 配置实时单元测试来访问设置向导。
在实时单元测试操作期间,会建立一个工作区——原始存储库的副本。在 Visual Studio 中进行的任何尚未保存的修改都将集成到这个工作区中。随后,实时单元测试启动构建,执行测试运行,并提供最新的代码覆盖率报告。
向导中的初始设置应解决文件复制源和目标。
让我们更深入地了解这个向导中的设置:
-
仓库根目录:这是包含所有 Live Unit Testing 所需文件的主要文件夹。它应包括所有源代码、二进制文件和测试所需的工具。如果解决方案文件不在该根目录内,可能需要调整以确保正确设置。
-
工作区文件夹:这是 Live Unit Testing 存储仓库副本的位置(默认设置为lut用于 Live Unit Testing)。默认情况下,此根目录创建在用户的家目录中,但可以根据偏好或特定要求进行自定义。
-
排除的文件:排除生成的工件被复制到 Live Unit Testing 工作区,以防止干扰常规构建。
-
构建选项:默认情况下,Live Unit Testing 使用多个 CPU 核心进行更快地构建。
-
测试用例超时:这允许设置一个特定的时间段,在此之后,如果测试超过分配的时间,则自动终止。
-
使用多个处理器:默认情况下,Live Unit Testing 会尝试利用多个处理器以加快测试执行速度。但是,如果您的机器出现减速或并行测试执行导致问题,如文件冲突,请取消选择此选项。
如果我们为排除文件选择<自定义>,我们可以定义自己的规则。设置向导将带我们到lutignore文件编辑器,其中不填充默认值。

图 1.20 – 配置 lutignore 文件
让我们根据 Microsoft 文档概述一下lutignore文件结构。
lutignore文件遵循与gitignore文件相同的格式。它应包括与构建过程中创建的文件夹或文件相对应的规则,确保它们不会被复制到 Live Unit Testing 工作区。对于大多数默认项目模板,提供的lutignore文件是足够的:
[BB]IN
[OO]BJ
这些规则防止将任何BIN或OBJ文件夹复制到 Live Unit Testing 工作区。
如果您的仓库只有一个构建文件夹,请在ignore文件中指定该文件夹:
[AA]RTIFACTS/
此规则确保ARTIFACTS文件夹不会被复制到 Live Unit Testing 工作区。
在您的仓库包含构建文件夹中的额外工具的情况下,也应使用匹配模式排除这些工具:
[AA]RTIFACTS/
![AA]RTIFACTS/TOOLS/
第一条规则排除了ARTIFACTS文件夹。第二条确保ARTIFACTS中的TOOLS子文件夹被复制,其中可能包含必要的工具和实用程序。
启动 Live Unit Testing
现在我们已经配置了 Live Unit Testing,它已打开并等待运行测试的播放列表。

图 1.21 – Live Unit Testing 控制台
使用笔形图标添加您的测试集。或者,您也可以通过点击消息底部的链接来添加所有测试。
回到我们之前的例子和我们的 ValidateMail() 函数,您可以在代码行的左侧看到绿色的勾选标记。这表明代码已被通过单元测试覆盖。

图 1.22 – 实时单元测试勾选标记
现在,我们可以继续进行我们的 TDD 迭代的重构步骤。
首先,我们将所有条件连接起来,并故意让测试失败:
public bool ValidateMail(string email)
{
return !email.Contains('@') &&
email.EndsWith('@') &&
!email.Contains('.') &&
email.EndsWith('.') &&
email.Contains("@.");
}
当我们更新文档时,实时单元测试会自动重新构建并更新测试状态指示器,将勾选标记变为红色叉号。

图 1.23 – 实时单元测试红色叉号
现在,我们可以修复我们的代码,勾选标记将自动出现。
在我们的案例中,这个过程非常顺利,但在更大的代码库和更多的单元测试中,它们可能在我们已经更改代码的情况下还没有完成运行。对于这个问题,您在 Visual Studio 的顶级菜单中有一个选项:工具 | 选项 | 实时单元测试 | 常规 。

图 1.24 – 额外配置 – 实时单元测试
多亏了这个窗口,您可以根据您的需求自定义您的实时单元测试体验。
我们可以看到,实时单元测试为我们提供了代码覆盖率的快速可视化。您可以通过导航到 Visual Studio 的测试菜单并选择分析所有测试的代码覆盖率来访问对代码库覆盖的更深入分析。有关更多信息,您可以查阅 Microsoft 文档,网址为 learn.microsoft.com/en-us/visualstudio/test/using-code-coverage-to-determine-how-much-code-is-being-tested?view=vs-2022&tabs=csharp 。
摘要
在本章中,我们讨论了单元测试作为非回归或开发过程的重要性。我们从提醒良好的单元测试实践和 TDD 开始,然后探讨了 Visual Studio 2022 提供的功能,以增强我们的生产力。
我们概述了测试资源管理器视图,展示了如何管理和组织单元测试。然后,我们深入探讨了新的智能感知功能,该功能提供工具,可以以最小的努力轻松地将非回归测试添加到旧代码库中,从而让我们有更多精力进行未来的重构。最后,我们学习了如何利用智能感知工具和实时单元测试来简化我们的测试驱动开发(TDD)体验。
在下一章中,我们将更深入地探索调试的世界,并了解 Visual Studio 2022 为高级策略提供的所有功能。
第二章:高级调试策略
在上一章中,我们探讨了单元测试和测试驱动开发(TDD),为构建可靠的代码奠定了坚实的基础。现在,我们的焦点转向 Visual Studio 中的高级调试策略领域。本章的目标是让我们掌握必要的工具和方法,以有效地处理错误。
在本章中,我们将涵盖以下主题:
-
掌握 Visual Studio 调试器
-
高级断点和数据检查
-
通过自动反编译和外部资源提升调试
-
远程调试
-
扩展调试功能超出代码库
-
掌握远程调试
到本章结束时,我们将能够显著更快地解决复杂错误,节省时间和精力。我们还将对代码有更深入的理解,从而构建更健壮、易于维护的应用程序。最后,我们将了解如何在生产环境中自信地工作,知道我们可以轻松处理意外问题。
因此,让我们一起踏上高级调试大师的旅程。通过我们获得的知识和技能,我们将能够直面任何调试挑战,确保代码的质量和性能。
技术要求
在编写本章时,我使用了以下版本的 Visual Studio:
-
Visual Studio Enterprise 2022 版本 17.12.0
-
预览 1.0
掌握 Visual Studio 调试器
调试是寻找和修复任何软件源代码中的错误或错误的过程。要正确完成这项任务,需要遵循几个步骤。
调试的第一步是定义问题。这包括识别其症状,比较预期与实际结果,确定其范围,评估其严重性和影响,并记录重现它的步骤。这种清晰度简化了故障排除过程。
重新生成错误通常是确定其原因的最有效方法。然而,如果无法这样做,请尝试检查它发生的环境,在线搜索错误消息,评估当时系统的状态,注意其发生的频率,并确定任何重复的模式。有效的调试技能对于提高软件质量和开发者生产力至关重要。
进入调试模式
为了帮助我们进行这些调试过程,现代集成开发环境(IDE)提供了强大的调试器。作为一名开发者,如果你曾经使用过 Visual Studio,那么你应该已经使用过 Visual Studio 中的调试器了。现在,让我们深入了解其最有价值的特性。
我已经设置了一个项目,通过使用调试器功能来分析代码的工作方式,我相信你可以在你当前的一个项目中尝试我们将会看到的内容。
启动调试器有两种常见选项:
- 以调试模式启动整个解决方案

图 2.1 – 调试模式
- 调试特定公共方法的单元测试

图 2.2 – 单元测试调试
第二个选项可能是我们在开发过程中节省编译时间的良好选择。无论我们的选择如何,首先要做的事情是通过在源文件左侧单击来设置断点以导航代码。我们将在本章后面讨论断点的详细信息。
简而言之,断点是在程序中故意停止或暂停的位置。
当我们设置断点并启动调试器(F5)时,我们可以观察方法的行为。以下是我们代码库中导航的三个主要选项的提醒:
-
步入(F11):此命令步入代码,意味着它进入当前行上被调用的方法或函数。如果有嵌套调用,它将进入最深层嵌套的调用。
-
步过(F10):此命令步过当前代码行,这意味着它执行当前行,然后停止在当前方法或函数的下一行。它不会进入任何方法或函数。
-
步出(Shift + F11):此命令从当前方法或函数中退出,这意味着它将执行方法或函数的其余部分,然后停止在方法调用之后的下一行。
在调试模式下,Visual Studio 2022 提供了多种方式,帮助我们能够在调试会话期间导航我们的代码应用程序。
高级调试导航
Visual Studio 2022 允许我们通过调试器光标来探索代码库的不同区域,以下列出了两个功能:
运行到光标(Ctrl + F10)
运行到光标处功能允许我们快速导航到代码中的特定位置,并执行到该点为止的代码。要使用运行到光标处,我们只需将光标放在我们希望执行停止的代码行上,然后右键单击并从上下文菜单中选择运行到光标处。或者,我们可以使用键盘快捷键Ctrl + F10。

图 2.3 – 运行到光标
重要的是要注意,我们放置光标的代码行必须是可到达的,这意味着它应该是应用程序运行时执行的代码的一部分。如果该行不可到达,运行到光标处命令将不起作用。
此命令将运行代码,直到达到光标的位置,但如果在光标之前设置了断点,调试器将停止在该断点处。
如果我们想通过调试器直接到达一行代码,自 Visual Studio 2022 以来,我们已经能够使用强制运行到 点击功能。
强制运行到点击
从 Visual Studio 2022 开始提供的强制运行到点击功能是一个强大的工具,允许我们在代码执行过程中跳过断点以及任何首次机会异常。当我们想要测试更新后的代码或专注于程序中的特定区域而不受断点的干扰时,这特别有用。
要使用强制运行到点击功能,我们需要在调试器中处于暂停状态。当调试器暂停时,我们可以在源代码中悬停在一个语句上,按住Shift键,然后选择运行执行到此处(由绿色箭头图标表示)。

图 2.4 – 运行执行到此处
当我们选择此选项时,应用程序将继续运行,直到达到光标位置,在此过程中发生的任何断点和首次机会异常都将暂时禁用。
当我们在应用程序中设置了多个断点并希望快速跳过它们以测试或调试代码中的特定点时,此功能特别方便。
现在我们已经使用调试器导航了代码库,我们需要了解每个步骤发生的情况。Visual Studio 提供了几个工具来帮助我们检查调试会话期间应用程序的状态。
理解调试工具
Visual Studio 调试器提供了一些窗口,有些比其他窗口更新,用于探索我们的变量和对象。让我们详细探讨这些窗口。
自动窗口
自动窗口显示由调试器自动评估的变量和表达式。它显示了当前作用域内局部变量和表达式的值。当拥有许多变量且不想将所有变量都添加到本地变量窗口中时,自动窗口非常有用。它仅根据我们当前的执行上下文评估最相关的变量。

图 2.5 – 自动窗口
在此示例中,我们有一个int apple.Id = 1;变量以及正在使用的apple和stockManager对象;自动窗口可能只显示它们及其值,而不是显示当前作用域中的每个变量。
接下来,让我们看一下本地变量窗口。
本地变量窗口
本地变量窗口显示了当前作用域中的所有局部变量。与仅显示变量子集的自动窗口不同,本地变量窗口列出了所有局部变量,无论其相关性如何。当我们需要查看特定断点处所有局部变量的确切状态时,这可能很有帮助。

图 2.6 – 本地变量窗口
在这里,本地变量窗口允许你在代码执行暂停时查看每个变量的值。
接下来,我们将查看监视窗口。
监视窗口
我们使用 观察 窗口来监视特定的变量或表达式。我们可以手动将变量或表达式添加到 观察 窗口中,并且当执行暂停时,调试器将评估它们。这在我们需要跟踪变量值随时间的变化或我们需要评估涉及多个变量的复杂表达式时特别有用。
要将表达式添加到 观察 窗口中,右键单击代码并选择 添加观察。我们也可以直接在 观察 窗口中键入或编写代码。

图 2.7 – 观察窗口
观察 窗口还可以在调试过程中修改变量的值,这有助于测试不同的场景。
调用栈窗口
现在,如果我们进入 UpdateProduct() 方法,我们可以在 调用 栈 窗口中跟踪序列。

图 2.8 – 调用栈窗口
Visual Studio 中的 调用栈 窗口是调试的关键工具,因为它允许我们查看导致程序当前执行点的函数或方法调用序列。此窗口对于理解执行流程和诊断代码中的问题至关重要。
下面是 Visual Studio 中 调用栈 窗口的一些关键功能:
-
查看调用栈:我们可以看到导致程序当前执行点的函数和方法调用序列。
-
切换堆栈帧:我们可以通过在 调用栈 窗口中右键单击一个帧并选择 切换到帧,或者通过双击帧来切换到不同的堆栈帧。这允许我们检查该帧中的代码和数据。
-
反汇编代码视图:要查看调用栈上函数的反汇编代码,只需右键单击该函数并选择转到 反汇编。
-
加载符号:Visual Studio 中的 调用栈 窗口具有为当前缺少符号的代码加载调试符号的能力。这些符号可能包括从微软的公共符号服务器获取的 .NET 或系统符号,或者位于我们计算机上的符号路径中的符号。
-
代码映射集成:Visual Studio Enterprise 提供了在调试过程中可视映射调用栈的功能。此功能使我们能够在新的代码映射中以图形格式观察当前的调用栈,该映射会随着调试的进行自动更新。这种视觉表示有助于更直观地理解我们代码的结构和流程,有助于识别潜在问题或优化区域。请注意,要将 CodeMap 扩展添加到 Visual Studio 中才能使用此功能。
最后,让我们看看 立即 窗口。
立即窗口
Visual Studio 中的立即窗口是一个古老且鲜为人知的调试工具,它允许我们在调试会话期间即时执行代码、评估表达式和打印变量值。

图 2.9 – 立即窗口
它旨在帮助进行动态代码评估和快速测试代码片段,而无需停止应用程序的执行。要使用立即窗口,可以通过转到调试菜单,选择窗口,然后选择立即窗口,或者按Ctrl + Alt + I来打开它。此窗口在调试应用程序时特别有用,因为它允许我们检查变量的值,调用函数,并执行语句,而无需逐行通过代码。
在调试期间有效地使用立即窗口的一些宝贵技巧:
-
立即窗口的调试方法:我们可以在方法中设置断点,并从立即窗口中调用它们以进行调试,即使我们已经通过了代码中的该点。请注意,我们可以使用运行到光标位置(Ctrl + Shift + F10)功能返回到同一作用域中的任何代码行,并使用F11进入方法以进行常规调试。
-
绕过访问规则:立即窗口不强制执行类访问规则,允许我们调用在常规代码中不可访问的私有、受保护和内部成员。然而,IntelliSense(内置的自动完成工具)仍然只会显示公共方法。
-
评估无副作用的表达式:在立即窗口中评估表达式可能会更改变量值并调用方法,这可能会引起副作用。为了避免这种情况,将无副作用(nse)附加到表达式,这将评估它而不会更改应用程序状态。
-
访问特殊调试变量:立即窗口可以显示特殊调试变量的值,例如\(exception**(当前抛出的异常)、**\)returnvalue(当前返回方法的返回值)和$user(当前操作系统用户和进程信息)。
-
评估 Make Object ID:在调试时,您可以在数据提示中为变量Make Object ID,这为对象创建一个唯一的标识符。此标识符可以在任何时间在立即窗口中评估,以查看对象值或存在状态的变化。
识别错误是我们调试过程中的一个基本步骤,但目标是修复它们。让我们探讨如何通过使用 Visual Studio 在线修复它们来提高生产力。
即时修复错误
为了在调试期间提高我们的生产力并避免停止和启动调试器来修复错误的需要,Visual Studio 2022 允许我们使用以下功能即时进行。
编辑并继续
编辑并继续是一种功能,允许您在应用程序处于断点模式时修改源代码。当您应用更改时,Visual Studio 会尝试重新编译修改后的代码并将这些更改应用到正在运行的应用程序中。这意味着您可以在不中断调试会话流程的情况下修复错误、添加功能或对代码更改进行实验。
这就是它的工作原理:
-
我们开始调试您的应用程序。
-
我们触发了断点并暂停了执行。
-
在暂停时,我们可以在编辑器中编辑代码。
-
编辑完成后,我们可以选择继续执行并应用新更改。
我们甚至可以将黄色的执行指针移动回去以改变执行流程并执行我们的编辑代码。
当我们在调试会话期间发现错误时,这个功能尤其有用,我们可以立即知道如何修复它。无需停止调试器、进行更改然后重新启动应用程序,您只需编辑代码并继续即可。
热重载
热重载是.NET 6中引入的新功能,并在 Visual Studio 2022 中得到支持。它允许我们在应用程序运行时更改代码,并且这些更改几乎会立即反映在运行的应用程序中。这就像编辑并继续,但有一些关键的区别:
-
热重载支持 UI 更新,而编辑并继续则不支持。如果我们更改了 UI 的布局或外观,热重载将更新正在运行的应用程序以反映这些更改。
-
热重载旨在与.NET 应用程序一起使用,包括 ASP.NET Core Web 应用程序和 Blazor WebAssembly 应用程序。
-
与编辑并继续相比,热重载需要更多的设置。我们需要在项目设置中启用它,并确保我们的应用程序与该功能兼容。我们将在下一章中更深入地探讨它。
-
使用热重载,我们可以立即看到我们的更改效果,这可以加快开发过程,尤其是在处理 UI 或前端代码时。
编辑并继续和热重载都是强大的工具,可以节省时间并减少在调试过程中停止和重新启动应用程序的挫败感。它们允许我们保持流畅的工作流程,并快速迭代代码,这可能导致更有效的解决问题和更快的开发周期。
现在我们已经掌握了导航调试器的技巧,对它们的窗口进行了概述,并执行了实时修复,让我们更深入地探讨两个提升调试能力的强大工具:高级断点和数据检查。虽然我们已经提到了它们,但请将此视为一次深入探讨,以便您能够精确地使用它们,并从代码行为中获得宝贵的见解。
高级断点和数据检查
Visual Studio 2022 中的高级断点是强大的工具,允许我们在调试会话期间检查和控制程序的执行流程。
理解断点的类型
Visual Studio 中的断点可以分为几种类型。具体如下。
条件断点
我们可以通过设置条件来控制断点的执行时机。这个功能自 Visual Studio 2005 以来就可用。我们可以右键单击断点符号并选择条件,或者右键单击代码旁边的空白处并从上下文菜单中选择插入条件断点。在断点设置窗口中,选择条件表达式、命中次数或过滤器,并在文本框中相应地设置条件表达式。

图 2.10 – 条件断点
在这个例子中,根据我们的设置,如果newQuantiy不等于product.QuantityStock,调试器将停止。
Tracepoints
自 Visual Studio 2005 引入以来,tracepoint作为一种断点变体,允许用户根据可定制的条件将信息记录到输出窗口,就像条件断点一样,而不会改变或暂停代码执行。Tracepoints 与 C#、Visual Basic、F#等托管语言以及 JavaScript 和 Python 等语言兼容。
要设置 tracepoint,只需单击位于所需行号左侧的空白处。将鼠标悬停在随后出现的红色圆圈上,然后单击齿轮图标以打开断点设置窗口。通过选择操作复选框来继续。此操作将红色圆圈转换为菱形,表示从传统断点转换为 tracepoint。

图 2.11 – Tracepoint
将我们想要记录的消息输入到在输出窗口中显示消息文本框中。如果我们想添加决定我们的消息是否显示的条件,我们可以选择条件复选框。至于条件断点,我们有三种条件选择:条件表达式、过滤器和命中次数。Tracepoints 对于调试很有用,因为它们允许我们记录信息,而不会在代码中添加打印语句或如Debug.WriteLine()之类的函数,从而不会使代码变得杂乱。
数据断点
数据断点允许我们作为开发者,在特定对象的属性值改变时暂停执行。这个特性在需要监控数据变化而不必手动逐行通过代码的调试场景中特别有用。数据断点可以为.NET Core 3.x或.NET 5+项目设置,并且对于跟踪对象属性的变化特别有用。
要在.NET Core 或.NET 5+项目中设置数据断点,我们开始调试并等待直到达到断点。然后,在自动、监视或局部变量窗口中,我们右键单击一个属性并从上下文菜单中选择当值改变时中断。

图 2.12 – 当值改变时中断
这将设置一个数据断点,当所选属性的值发生变化时触发。
数据断点受硬件和内核限制。Windows 内核和底层硬件对可以同时设置的数据断点数量有限制。这些限制确保我们的调试体验保持高效和响应。
需要注意的是,数据断点依赖于特定的内存地址,并且变量的地址可能会从一个调试会话变化到下一个调试会话。因此,数据断点在每个调试会话结束时自动禁用。如果我们对一个局部变量设置了数据断点,当函数结束时,断点仍然启用,但内存地址不再适用,这可能导致不可预测的行为。建议在函数结束时删除或禁用此类断点,以避免混淆。
Visual Studio 2019 中为 .NET Core 引入的数据断点标志着这一功能的开始,这使得它在我们使用 .NET Core 3.x 或 .NET 5+ 时成为一个有价值的工具。
函数断点
自从 Visual Studio 2012 以来,我们能够在函数上设置断点,这在我们知道函数名但不知道其位置,或者有重载函数时很有用。要设置函数断点,请选择调试 | 新建断点 | 函数断点,或者按Ctrl + K,然后B。

图 2.13 – 函数断点
输入完全限定的函数名,包括重载函数的参数类型,或使用!符号指定模块。在这里,我们为StockManager类的SearchProducts方法设置了一个断点。
依赖断点
Visual Studio 2022 介绍了设置依赖断点的可能性,这是一个强大的调试功能,它允许我们仅在另一个特定的断点首先被触发时暂停程序的执行。这在复杂的调试场景中特别有用,例如当我们处理多线程应用程序或当我们想专注于调试应用程序特定部分的代码时。
要设置依赖断点,我们首先需要确定当前断点将依赖的断点。然后,我们将鼠标悬停在断点符号上,选择设置图标,并在断点设置窗口中选择仅当以下断点被触及时启用。

图 2.14 – 仅当以下断点被触及时启用复选框
从下拉菜单中,我们选择我们希望当前断点依赖的先决断点。设置完成后,我们可以关闭对话框。
另一种设置依赖断点的方法是使用右键单击上下文菜单。我们在代码左侧的空白处右键单击,并从上下文菜单中选择插入依赖断点。

图 2.15 – 插入依赖断点
重要的是要注意,如果我们的应用程序中只有一个断点,依赖断点将不起作用。如果先决断点被删除,依赖断点将被转换为普通行断点。
此功能旨在通过允许我们专注于与当前调试任务相关的代码特定部分来简化我们的调试过程,从而在调试过程中可能节省时间和精力。
临时断点
Visual Studio 2022 中的临时断点是一个强大的调试功能,它允许我们作为开发者,在特定位置暂停代码的执行仅一次。一旦在调试会话中命中断点,它将自动禁用自己,这使得它在需要检查特定条件或行为而不需要重复命中相同断点的情况下非常理想。
要设置临时断点,我们首先需要确定当前断点所依赖的断点。然后,我们将鼠标悬停在断点符号上,选择设置图标,并在断点设置窗口中选择一旦命中则禁用断点。此操作将配置断点在调试会话中命中后自动禁用自己。

图 2.16 – 一旦命中则禁用断点
或者,我们也可以通过在断点空白处右键单击并从上下文菜单中选择插入临时断点来直接设置临时断点。
Visual Studio 2022 中临时断点的引入通过提供一种工具来检查代码中的特定点,而不需要在它们被命中后手动删除或禁用断点,从而增强了我们的调试体验。此功能特别适用于验证假设、检查执行流程或在我们调试过程中验证变量的特定状态。
现在我们已经了解了所有关于断点的知识,让我们学习如何组织它们。
组织我们的断点
我们可以使用标签在断点窗口中对断点进行排序和筛选。右键单击断点并选择编辑标签…以添加或更改标签。

图 2.17 – 编辑标签…
然后,在断点窗口中,我们可以检索我们的标签以进行筛选和组织。

图 2.18 – 带标签的断点
在这个例子中,我给我的条件断点命名为UpdateQuantity。
既然我们已经知道根据我们的需求使用哪些断点,让我们看看如何高效地检查数据。
检查数据
正如我们之前所看到的,Visual Studio 中的 监视 窗口是一个强大的调试工具,它允许我们在程序执行期间监控变量和表达式的值。当我们想要关注代码执行时变量值的变化时,它尤其有用,这在调试复杂的逻辑或性能问题时特别有帮助。
虽然 监视 窗口为监控变量提供了一个专用空间,但 Visual Studio 还为我们提供了一种更直接的选择:数据提示。这些方便的弹出窗口直接出现在代码编辑器中,直接显示变量值。
要利用 DataTips,只需将鼠标悬停在代码中的任何变量名上。然后,会出现一个工具提示,显示该变量的当前值。

图 2.19 – 显示数据提示
在某些场景中,例如 图 2.19 中所示,在大型列表中定位感兴趣的具体项目可能具有挑战性。
锁定属性
当查看包含大量复杂数据的数据列表时,可能很难集中精力关注所需的数据部分。解决方案是利用 可锁定属性 功能,该功能也存在于 监视 窗口中。为了实现这一点,我们展开一个变量并锁定我们感兴趣的属性。例如,如果我们对产品的名称感兴趣,我们可以将其锁定以方便引用。

图 2.20 – 锁定名称属性

图 2.21 – 带有锁定名称的产品列表
现在,无论何时我们使用 DataTips 检查此对象,即使在 监视 窗口中,锁定属性都会替换对象名称,直到我们取消锁定。

图 2.22 – 监视窗口中的锁定属性
现在,我们可以轻松访问我们想要检查的产品。此外,我们还可以使用位于产品对象旁边的锁定图标来保持弹出窗口可见。

图 2.23 – 数据提示锁定
在这个例子中,我锁定了产品的 名称 和 Id 属性,这样我们就可以在循环执行期间监控其行为。
编辑值
DataTips 使我们能够编辑非只读变量的值,这在验证某些场景时可能很有用。为此,我们只需单击属性值以更新它。

图 2.24 – 在 DataTips 中编辑值
数据提示还允许我们编辑非只读变量的值,这对于验证某些场景可能很有用。此功能也适用于监视窗口,尽管它不在局部或自动窗口中。
虽然在我们自己的代码中进行细致的调试实践至关重要,但有时真正的罪魁祸首隐藏在外部组件中。理解它们的行为是解锁难以捉摸的 bug 和构建真正稳健解决方案的关键。让我们探讨从版本 17.7 开始的 Visual Studio 如何帮助我们在这个方面取得进展。
使用自动解耦和外部资源提升调试
Visual Studio 2022 通过引入自动解耦和外部资源显著增强了调试体验。这些功能允许开发者以与自己的代码相同的轻松程度调试外部代码,如 .NET 库或NuGet包。
自动解耦
自动解耦是一个将编译的二进制代码转换为高级编程语言(如 C#)的功能,使我们能够像处理自己的代码一样检查、调试和修复外部代码中的问题。这在源代码不可用或我们需要检查第三方库中的代码时尤其有用。
自动解耦的工作原理
调试器使用ILspy反编译器引擎实时反编译外部代码并将其纳入调试会话。调试器首先在我们的机器上查找本地外部资源,然后使用 PDB 文件中的源链接或源服务器信息来加载源代码。如果这些方法失败,调试器将回退到反编译代码。
控制自动解耦
在过去,.NET 包作者可以通过实现SuppressIldasmAttribute属性来控制其代码是否可以被反编译。尽管从 .NET 6+ 开始此属性已过时,但 Visual Studio 仍然尊重它。
自动解耦的限制
在尝试反编译 .NET 程序集时可能会遇到问题,例如变量名称不准确或不可用变量进行评估。这些限制在调试优化或发布程序集时可能更为明显。
外部资源
Visual Studio 中的外部资源功能允许我们调试并单步执行不属于我们解决方案的依赖 NuGet 或 .NET 库中的代码。这是通过在解决方案资源管理器中添加外部资源节点来实现的,该节点在调试期间出现,并显示包含源链接或源服务器信息的已加载符号的管理模块的源。
我们可以在解决方案资源管理器中找到它们位于解决方案顶部节点下方:

图 2.25 – 外部资源节点
这里有一份关于利用此功能的全面指南:
-
使用外部源:外部源节点组织来自不同调用栈的反编译外部代码模块,使我们能够在其中导航和设置断点。这使得调试外部代码与调试我们自己的代码一样无缝。
-
启用外部源:要调试外部源,我们可能需要启用加载所有模块,以便调试器为所有模块加载符号。如果需要,我们还可以通过从顶部菜单的调试 | 窗口 | 模块进入,从模块窗口手动加载模块。
-
下载源代码:如果我们双击外部源节点中的某个项目,可能会提示从服务器下载源代码。接受后,我们可以在编辑器中查看源代码。
自动反编译和外部源使得我们更容易调试外部代码,这在处理复杂库或尝试解决第三方代码中的问题时尤其有益。这些功能简化了我们的调试过程,减少了我们在理解和导航外部代码上花费的时间。包作者可以使用SuppressIldasmAttribute属性来防止其代码被反编译,从而确保他们对其知识产权的控制。然而,调试反编译代码可能并不总是像调试源代码那样准确,可能会出现诸如变量名不准确或变量不可用等问题。此外,单步执行反编译代码可能并不总是与原始源代码对齐。
通过利用这些功能,Visual Studio 2022 提供了更全面的调试体验,使我们能够更有效地诊断和解决应用程序中的问题。
并发调试
多线程是一种技术,其中进程分为多个线程,从而允许更好的性能,尤其是在具有多个处理器或核心的系统上。然而,管理多个线程可能具有挑战性,因为它们可能需要并发访问共享资源,从而导致潜在的死锁等错误。调试此类问题可能既困难又耗时。
在本节中,我们将学习如何通过使用线程窗口和处理并行调试来解决这个问题。
为了做到这一点,我们将创建一个简单的控制台应用程序,调用十个简单的线程。以下是我们将用于示例的代码:
for (int i = 0; i < 10; i++)
{
CreateThreads();
}
static void CreateThreads()
{
Dummy dummy = new Dummy();
Thread dummyCaller = new Thread(
new ThreadStart(dummy.Instance)
);
dummyCaller.Start();
Console.WriteLine("New thread called "
+ "starting the new Dummy thread.");
}
public class Dummy
{
static int count = 0;
public void Instance()
{
Console.WriteLine(
"Dummy.Instance is running on another
thread.");
int data = count++;
Thread.Sleep(3000);
Console.WriteLine(
"The instance method called by the worker
thread has ended. " + data);
}
}
代码演示了在 C#中创建和执行多个线程的过程,每个线程运行一个Dummy类的Instance方法实例。
首先,我们将在Instance方法上的Thread.Sleep(3000)处设置断点,并以调试模式启动我们的项目。
我们可以通过在调试工具栏上激活显示源代码中的线程按钮来跟踪线程。

图 2.26 – 显示源代码中的线程
这将在窗口的左侧显示线程创建者图标。当我们悬停在它们上面时,我们可以查看每个停止线程的名称和线程 ID 号。

图 2.27 – 线程列表
通过右键单击其中一个线程,我们可以访问不同的操作类型以在线程之间导航,如下所示:
-
标记 / 取消标记
-
冻结 / 解冻
-
切换到线程

图 2.28 – 操作线程
当我们标记线程时,它使我们能够专注于一个线程,同时忽略其他线程。
为了解决并发问题并控制线程执行工作的顺序,我们必须使用冻结和解冻功能,允许我们挂起和恢复线程。
此外,切换到线程功能允许我们在逐步调试中从一个线程跳转到另一个线程。
关于常见的调试过程,Visual Studio 提供了一个名为并行监视的监视窗口。我们可以通过点击顶部菜单栏的调试 | 窗口 | 并行监视 | 并行监视 1来访问它。

图 2.29 – 并行监视
在这里,我们可以通过在<添加监视>单元格中输入它们的名称来添加数据到监视。此外,我们可以通过双击我们感兴趣的线程行轻松地切换到线程。右键单击允许我们访问标记和冻结功能。位于左上角的标记按钮使我们能够过滤并仅显示标记的线程。
Visual Studio 提供的另一种高效跟踪线程的视图是并行堆栈窗口。要访问它,我们使用调试菜单,可以通过点击调试 | 窗口 | 并行堆栈来访问。

图 2.30 – 并行堆栈
此窗口提供了线程和任务视图,显示每个线程的调用堆栈信息。当前线程由一个黄色箭头指示,使我们能够轻松地跟踪每个线程的路径。这些信息也可以通过转到调试 | 窗口 | 线程来以列表格式在线程窗口中查看。
最后,我们可以利用条件断点,这允许我们根据各种条件设置断点,例如线程名称或 ID。当需要对每个线程独有的数据进行条件设置时,这个功能特别有用。在调试过程中,尤其是在关注特定数据值而不是单个线程时,这是一个常见的做法。
现在我们已经探索了 Visual Studio 2022 关于调试的技术和工具,让我们看看如何通过利用远程调试功能来解决著名的“在我的笔记本电脑上它工作”的问题。
远程调试
远程调试是 Visual Studio 中的一个强大功能,允许我们调试在不同机器、设备或环境中运行的应用程序。当我们需要解决在生产环境中或在我们无法本地访问的不同平台上发生的问题时,这尤其有用。
为了有效地利用此功能,我们需要确保在本地和远程机器上都安装了 Visual Studio。我们需要通过安装兼容的 Visual Studio 版本并允许通过防火墙设置进行远程连接来配置远程机器。
在本地机器上,我们通过指定远程机器的地址和(如果需要)凭据,在 Visual Studio 的设置中启用远程调试。为此,我们转到我们想要调试的应用程序的项目属性,并导航到 调试 选项卡。

图 2.31 – 项目属性 | 调试选项卡
在这里,我们可以点击 打开调试启动配置文件 UI 链接。一旦进入 启动配置文件 窗口,我们可以勾选 使用远程机器 复选框,这将显示两个额外的字段,允许我们配置远程连接:

图 2.32 – 使用远程机器复选框
在一个关键情况下,如果在实时生产服务器上调试 Web 应用程序,能够访问生产服务器的调试器变得至关重要。
将应用程序部署到生产服务器,确保安装了所有必要的组件。之后,我们需要在服务器上配置 Visual Studio 以进行远程调试,并相应地调整防火墙设置。在本地机器上的 Visual Studio 中,通过输入远程机器的地址和凭据来附加到远程进程。
然后,我们可以调试应用程序,选择 Web 应用程序的过程,并像往常一样进行调试,包括设置断点和检查变量。最后,我们可以在调试过程中重现问题,一旦确定问题,就修复它,并部署更新后的应用程序。
远程调试简化了在生产环境类似环境中诊断问题,而不会干扰实时流量。访问生产数据有助于理解问题的上下文。应实施安全措施以保护敏感信息。注意性能影响,在非高峰时段或在测试环境中安排调试。利用远程调试通过解决传统方式无法访问的环境中的问题,提高了应用程序的可靠性,增强了整体质量和稳定性。
通过使用远程调试,我们可以有效地诊断和修复在无法直接访问代码或数据的环境中发生的问题,从而提高我们应用程序的可靠性和质量。
摘要
本章深入探讨了 Visual Studio 2022 中强大的高级调试策略世界,为您提供了应对甚至最复杂代码的有效技能。我们探讨了各种调试工具和技术,这些对于识别和解决代码中的问题至关重要。
我们从掌握导航代码的艺术开始,重点关注断点、单步执行模式和调用栈,这些都是定位错误来源的关键。本章还介绍了实时代码修改的概念,允许您通过诸如“编辑并继续”和“热重载”等功能,动态修复错误并实时实验代码更改。我们不仅限于调试自己的代码;还探讨了自动反编译和外部源的优势,这些功能使得外部库和 NuGet 包的调试变得无缝。此外,本章还涵盖了远程调试技术,这是一种允许您在不影响实时流量的情况下,在生产环境类似环境中诊断和修复问题的技术。通过掌握这些高级调试技术,您可以更快地解决复杂错误,从而减少开发时间和挫折。
在下一章中,我们将根据第一章中看到的 TDD 循环继续我们的旅程。在用调试修复我们的代码之后,我们将深入探讨将代码塑造成最佳形态的艺术。我们将开始一段在 Visual Studio 2022 中进行高级代码分析和重构的旅程。
第三章:高级代码分析和重构
本章通过专注于 Visual Studio 2022 中的高级代码分析和重构技术,提升了我们的技能。
通过 Roslyn 驱动的静态代码分析来理解代码分析的基础,为识别漏洞和确保代码正确性奠定了坚实的基础。此外,借助内置的 IntelliCode,它利用机器学习来优化代码库,你将学习如何有效地提高可维护性和可扩展性。
除了这些基础概念之外,我们还将深入探讨代码指标的重要性,为你提供评估项目可维护性和安全状态的有价值见解。通过使用这些指标,你将获得所需的战略远见,以便做出明智的决定并对代码库进行有针对性的改进。
在本章中,我将通过实际的代码审查重构案例研究来阐述这些概念。通过探索 Visual Studio 工具的实际应用,你不仅能够掌握理论概念,还能了解如何在日常开发工作中有效地实施它们。
到本章结束时,你将掌握提升代码质量、增强安全实践和简化维护工作所需的知识和工具,所有这些都在熟悉的强大环境中完成,即 Visual Studio。
在本章中,我们将涵盖以下主要主题:
-
理解 Visual Studio 中的代码分析
-
利用静态代码分析进行质量保证和安全
-
利用 IntelliCode 进行代码重构
-
使用代码指标进行可维护性和安全性
-
重构案例研究
技术要求
在编写本章时,我使用了以下版本的 Visual Studio:
-
Visual Studio Enterprise 2022,版本 17.12.0
-
预览 1.0
本章的代码文件可以在github.com/PacktPublishing/Mastering-Visual-Studio-2022/tree/main/ch03找到
理解 Visual Studio 中的代码分析
首先,让我们讨论 Visual Studio 和 .NET 如何分析我们的代码。
Visual Studio 2022 中的代码分析旨在帮助我们提高代码质量。它提供了一些工具和指标来分析和增强代码的可维护性、可读性和性能。通过识别潜在问题并提出改进建议,它旨在简化开发过程,减少错误,并提高整体代码质量。
Visual Studio 2022 可以通过两种主要方式执行代码分析:
-
遗留分析(FxCop 静态分析):这种方法分析编译后的代码以识别问题。这是一个过时的方法,它只在代码编译后进行检查。
-
基于.NET 编译器平台的代码分析器:这些是现代分析器,在您键入时实时分析您的代码。它们是动态的,可以提供实时反馈,使在开发早期阶段捕捉和修复问题变得更容易。
现在,让我们深入了解.NET 编译器平台,也称为Roslyn,它彻底改变了 Visual Studio 2022 中的代码分析能力。Roslyn 是一个平台,它将 C#和 Visual Basic 编译器的代码分析能力暴露给开发者。它提供了一套 API,允许创建专注于代码分析、重构和转换的工具和应用程序。
这里是 Roslyn 的一些好处:
-
丰富的语言支持:Roslyn 支持 C#和 Visual Basic 语言,提供全面的语言特性和语法支持,用于构建自定义的开发者工具和扩展。
-
程序化代码操作:使用 Roslyn,我们可以通过.NET API 程序化地分析、重构和生成代码,使它们能够自动化重复性任务,并提高代码质量和一致性。
-
IDE 可扩展性:Roslyn 允许开发自定义的 IDE 扩展和工具,增强 Visual Studio 和其他.NET IDE 的功能,扩展其能力以支持专门的流程和开发场景。
-
开源社区:Roslyn 是一个托管在 GitHub 上的开源项目,它促进了开发社区的协作和贡献。开发者可以向 Roslyn 代码库贡献增强功能、错误修复和新功能,推动平台创新和进化。
Roslyn 显著降低了创建专注于代码的工具和应用程序的难度,为包括元编程、生成和转换代码、将交互式功能集成到 C#和 Visual Basic 语言中以及将这些语言嵌入到特定领域在内的各个领域的创新铺平了道路。
Roslyn 的工作原理
Roslyn 通过将其分解为不同的组件而彻底改变了传统的编译器结构。此外,它通过镜像编译器内部过程的 API 提供对编译器管道每个阶段的访问。
这里是如何组织这种映射的说明:

图 3.1 – 编译器 API 和编译器管道
编译器 API 和编译器管道提供对几个关键阶段的访问:
-
解析阶段:源代码经过标记化和解析,生成遵循语言语法的语法树。
-
声明阶段:从源代码和导入的元数据中分析声明以构建命名符号。这些符号组织成一个层次符号表。
-
绑定阶段:代码中的标识符与符号匹配,生成反映编译器分析的语义模型。
-
Emit Phase:编译器累积所有相关信息,并以汇编的形式输出。这个汇编通过一个 API 表示,该 API 生成中间语言(IL)字节码。
这种模块化方法允许全面访问编译器管道每个阶段的详细信息。它赋予开发者丰富的代码分析和操作能力。三个阶段的编译器 API(语法树、语义模型和工作区级别)在促进稳健的代码分析方面尤其重要。
首先,语法树作为源代码结构的基石表示,包括词汇和语法元素。它们在软件开发的各种阶段都至关重要,包括编译、代码分析、绑定、重构和 IDE 功能。语法树提供了对源信息的完整反映,与原始文本保持一致,确保不可变性和线程安全。这促进了源代码的自然操作,而无需直接进行文本编辑。
转向语义层面,语义模型深入挖掘代码背后的含义。它在一个源文件中捕获所有语义细节,揭示了符号引用、表达式类型、诊断(错误和警告)、源区域内的变量流以及其他细微方面。通过封装语言规则,该模型使得源代码中的程序元素与预编译库中的元素之间的区别更加清晰。
在工作区级别,一个中心枢纽组织整个解决方案的信息,简化了代码分析和重构过程。这一层将项目数据整合到一个统一的对象模型中,无需文件解析、配置调整或项目间依赖关系管理即可无缝访问编译层对象模型。关键的是,它为集成开发环境(如 Visual Studio)中稳健的代码分析和重构工具的发展奠定了基础。
Visual Studio 2022 如何使用 Roslyn?
Visual Studio 2022 使用 .NET 编译器平台(Roslyn)在开发者编写代码时实时分析并重构 C# 或 Visual Basic 代码。此过程集成到开发环境中,提供对代码样式、质量、可维护性、设计和其他问题的即时反馈。在接下来的章节中,我们将学习 Visual Studio 2022 如何利用 Roslyn 进行分析和重构。
使用 Roslyn 分析器进行分析
Visual Studio 2022 包含内置的代码样式分析器(IDExxxx,例如,IDE0001)和代码质量分析器(CAxxxx,例如,CA1822),它们在所有打开的文件的设计时检查你的代码。这些分析器是 .NET 5 SDK 的一部分,默认启用。
我们可以将外部分析器,如StyleCop、Roslynator、XUnit Analyzers和SonarAnalyzer,作为 NuGet 包或 Visual Studio 扩展安装。这些分析器扩展了内置功能,允许进行更专业的检查和规则。
此外,我们使用带有代码修复的 Analyzer模板创建自己的自定义分析器,该模板包括一个 VSIX 扩展和一个用于分析器的独立项目。这可以通过 NuGet 进行部署。这允许我们创建自己的自定义分析器。分析器可以在匹配的代码下方显示波浪线并在错误列表中添加条目,可选的代码修复。这种方法允许更集成的开发体验,在 IDE 中直接提供反馈和修复。
对于不需要与 Visual Studio 集成的分析场景,例如在构建服务器上,我们可以使用独立代码分析工具模板。此工具打开解决方案工作区并分析项目,无需在项目中或 IDE 中安装 VSIX 扩展或 NuGet 包。
使用 Roslyn 进行重构
Roslyn 的语法 API 将 C#代码解析成节点树(类节点、方法节点等),使得对代码结构的详细操作成为可能。这个 API 对于自动化代码重构至关重要,例如自动化应用程序迁移到.NET Core。
SyntaxEditor类用于对代码树应用更改。它确保当一个节点被替换或删除时,所有子节点都会相应地更新,避免冲突和异常。这对于需要根据某些模式或规则修改代码的脚本重构特别有用。
Visual Studio 中的代码重构模板允许创建一个与 IDE 中的快速操作菜单集成的 VSIX 扩展。这使得开发者可以直接从编辑器应用快速代码修复,而无需定义额外的分析器 ID 或在错误列表中显示条目。
现在我们已经了解了 Visual Studio 如何使用 Roslyn 帮助我们分析和重构代码,让我们更深入地探讨如何使用静态代码分析进行质量保证和安全。
利用静态代码分析进行质量保证和安全
对于目标.NET 5 或更高版本的 Visual Studio 项目,默认启用了内置的代码质量分析功能。但是,我们可以通过在.csproj文件中添加并设置为true的EnabeNETAnalyzers属性来为我们的旧.NET 项目启用它。
静态代码分析促进了开发团队内部的持续改进和协作文化。通过提供可操作的建议和见解,这些工具促进了建设性的代码审查,促进了知识共享,并最终提高了开发者的技能和熟练度。
理解如何在 Visual Studio 中使用代码分析
代码质量分析将检查我们的代码库的安全性、性能、设计和其他潜在改进领域。默认情况下,分析会自动运行,因此我们可以在键入时通过代码下的波浪线或错误列表窗口直接看到错误、警告和信息。
如果我们编写的代码像图 3.2中所示的那样,我们将看到波浪线出现:

图 3.2 – 信息波浪线
在此示例中,分析器通知我们我们的using语句可以根据 C# 8.0 引入的功能进行简化。
分析规则组织到以下类别:设计、文档、全球化、可移植性和互操作性、可维护性、命名、性能、可靠性、安全性、样式和用法。您可以在 Microsoft 文档中找到有关每个规则类别的详细信息:learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/categories。
每个规则都有一个严重级别,用于确定其行为:
-
默认:这是已启用但未设置特定严重性的规则的默认严重级别。这通常意味着规则是激活的,并将报告问题,但确切的行为(例如,是否被视为警告、错误或建议)取决于规则的配置或工具的默认行为。
-
错误:当规则设置为错误严重级别时,任何违反规则的行为都将被报告为错误。这意味着代码将不会编译,直到问题得到解决。错误通常用于在代码被认为正确之前必须修复的关键问题。
-
警告:设置为警告的规则将报告违规行为为警告。警告不会阻止代码编译,但通常用于指示应解决以改进代码质量或可维护性的潜在问题。警告可以配置为在特定构建配置中视为错误,允许开发者对生产代码强制执行更严格的标准。
-
建议:建议严重级别的规则报告的问题不是关键的,但可以改进代码。这些规则通常用于风格问题或不是必需但建议的做法。建议通常与自动应用推荐更改的代码修复结合使用,使开发者更容易提高代码质量。
-
静默:设置为静默的规则将不会报告任何问题,实际上禁用了该规则。这对于与你的项目无关的规则或当你想暂时禁用规则而不从配置中删除它时非常有用。
-
无:此严重性级别类似于静默,但用于明确表示规则不应应用。这是一种明确表示规则有意禁用的意图的方式。
让我们看看如何使用严重性级别来提高我们项目的质量。
调整严重性级别
我们可以通过通过错误列表右键单击建议并选择设置严重性来调整规则的严重性级别。
这使我们能够优先考虑并自定义 Visual Studio 如何呈现和处理由规则识别的潜在问题。根据项目需求和开发环境,调整严重性级别可以集中关注关键问题,同时最大限度地减少对影响较小问题的干扰。

图 3.3 – 设置严重性选项
此操作将在我们的解决方案根目录中生成一个.editorconfig文件,其中包含覆盖的严重性规则,我们可以与我们的团队共享以确保一致的编码实践。

图 3.4 – 生成的 .editorconfig 文件
调整严重性级别的另一种方法是通过灯泡上下文菜单,它还通过快速操作提供代码修复。

图 3.5 – 使用灯泡图标设置严重性
在代码审查期间,我们可能会遇到如图 3.6* 所示的可以改进的实践。

图 3.6 – 金字塔代码
例如,一个金字塔代码结构可能不会触发波浪线,但 IDE 可能会建议简化一个if语句(IDE0046)。如果您想强制执行特定的编码标准,可以将此规则的严重性级别设置为错误。

图 3.7 – 更改 IDE0046 的严重性级别
同样,当我们和我们的团队成员遇到此规则时,我们被迫重构我们的代码。我们可以注意到 Visual Studio 为此规则提供了四种代码修复:
-
转换为条件表达式:此修复将if-else语句转换为条件(三元)表达式。
-
反转 if:此修复反转 if 语句的条件并交换代码块。
-
转换为 switch 语句:此修复适用于您有基于相同变量或表达式的多个条件时。它将if-else链转换为switch语句,这对于处理基于相同变量的多个条件来说更易读且易于维护。
-
转换为 switch 表达式:与转换为switch语句类似,此修复将if-else链转换为switch表达式,这是一种更简洁且功能更强大的处理多个条件的方法。它从 C# 8.0 开始可用。
为了更好的可读性,我更喜欢在这个例子中使用 Invert if,但 IDE0046 规则强制将其转换为条件表达式。请记住,这只是一个例子,我们可以根据我们的需求调整解决方案中分析规则的程度。
正如我们所见,调整严重程度级别会生成一个包含我们自定义配置的.editorConfig文件。让我们探索如何生成这样的文件,以便轻松地将我们的 Visual Studio 设置与团队共享。
生成 .editorconfig 文件
如果你在团队环境中工作,我建议你生成一个可以根据你的需求进行调整的.editorConfig文件。
要生成一个.editorconfig文件,我们在我们的解决方案上右键单击,然后在上下文菜单中选择添加 | 新建 Editor Config 。

图 3.8 – 新的 EditorConfig
这将生成一个新文件,其中将包含我们 IDE 的所有配置。在这个文件中,我们将检索分析器的所有规则。

图 3.9 – EditorConfig 分析器
这使我们能够轻松列出并设置每个规则的严重程度级别。
在这里,我们可以看到 Visual Studio 分析器提供了关于安全的 94 条规则。这些规则涵盖了 OWASP Top Ten 的所有主题,以及更多。OWASP Top 10 作为开发者和网络应用安全的一个广泛认可的参考文档,它基于行业内的集体协议,突出了网络应用面临的最重大的安全漏洞。
进一步阅读
我们可以在 Microsoft 文档中找到所有安全规则:
现在我们已经学习了如何使用静态代码分析,让我们深入了解一个新特性。确实,Visual Studio 2022 现在将 IntelliCode 作为一个内置特性集成,对所有订阅者可用。让我们探索它是如何工作的,以及我们如何利用其功能。
利用 IntelliCode 进行代码重构
作为开发者,我们需要不断重构我们的代码来改善其结构、可读性或性能,尤其是在我们使用 TDD(测试驱动开发)时,需要关注第一章中解释的流程。
一个显著提高了我们重构过程的工具是IntelliCode,它使用人工智能和机器学习提供智能建议并自动化重复性任务。IntelliCode 现在已集成到 Visual Studio 2022 的 C#中。在本节中,我们将探讨使用 IntelliCode 进行有效代码重构的策略,借鉴我们的经验和洞察。
首先,我们需要确保我们在 Visual Studio 中安装了 IntelliCode,通过顶部菜单栏的 选项 菜单进行,即 工具 | 选项 | IntelliCode 。

Figure 3.10 – IntelliCode Options
如果你在 选项 菜单中找不到 IntelliCode,请通过 Visual Studio 安装程序安装它,勾选 IntelliCode 复选框。

Figure 3.11 – Visual Studio Installer IntelliCode
现在,我们已经确保 IntelliCode 在 Visual Studio 中已启用,让我们探索它如何增强我们的编码体验。
使用整行自动补全预测代码
IntelliCode 是在 Visual Studio 2022 中引入的,提供带有建议的整行自动补全。此功能旨在简化开发过程,提高代码质量,并提高生产力。
以下图像展示了整行自动补全:

Figure 3.12 – Whole-line autocompletion from typing
在 Figure 3 .12 中,我们可以看到根据上下文生成的 灰色文本行预测。该预测基于大量公共、开源的 GitHub 仓库。IntelliCode 的建议与 IntelliSense 中的建议无缝集成。这些 IntelliCode 建议通过位于建议左侧的 黑色星号 图标突出显示,易于识别。
如果我们选择了一个不同于整行自动补全提供的建议,IntelliCode 将根据我们的选择生成一个新的预测。

Figure 3.13 – Whole-line autocompletion from IntelliSense
要接受整行自动补全,我们只需按 Tab 键或点击出现在建议上方的 箭头。我们可以按 Esc 或 Delete 键来取消它。
IntelliCode 在本地机器上运行,提供整行自动补全,这增强了代码安全性和对属性的考虑,与 ChatGPT 和其他在线 AI 预测工具不同,这些工具是在行内生成的。
现在,我们已经看到 IntelliCode 如何帮助我们生成代码,让我们探索它如何通过提供直接访问文档来帮助我们理解代码。
访问 GitHub 文档
当使用外部库或代码块时,我们可能会遇到不知道如何高效使用的函数。IntelliCode 提供了一个有用的功能,称为 API 使用示例,它提供了如何有效使用这些函数的实际示例。
要激活此功能,请转到 选项 菜单(见 Figure 3 .10 )并勾选 启用 API 使用示例 。
现在,我们可以将光标悬停在想要了解更多信息的函数上,我们会看到一个标记为 GitHub 示例 和文档 的链接:

图 3.14 – GitHub 示例和文档链接
点击链接(GitHub 示例和文档)后,会打开一个侧边固定窗口,展示通过几个 GitHub 仓库实现方法示例:

图 3.15 – GitHub 示例
此功能帮助我们根据其他项目中实现的示例来规划重构,利用其他开发者的经验。
在下一节中,让我们深入了解代码度量,这些度量指向我们项目中需要重构以改善可维护性和质量的部分。
代码度量、可维护性和安全性
作为开发者,我们依赖代码度量来评估软件系统的质量。这些定量措施为我们代码的各个方面提供洞察,如复杂度、可维护性和安全性。通过理解这些度量,我们可以识别可能需要改进的区域,确保我们的代码库保持可管理、安全且高效。
理解度量
Visual Studio 允许我们生成包含度量值列表的报告,如下所示:
-
可维护性指数评估代码的可维护性,给出 0 到 100 的分数,分数越高表示可维护性越好。评分用颜色编码:绿色(20-100)表示良好,黄色(10-19)表示中等,红色(0-9)表示低。
-
循环复杂度通过计算代码的不同流程路径来衡量代码的结构复杂度。高复杂度表明需要更多的测试以实现良好的覆盖率并降低可维护性。
-
继承深度衡量有多少个类相互继承,数值越低越好,以防止广泛的变化。
-
类耦合衡量类之间的连接紧密程度,高耦合表示设计不佳。
-
源代码行数计算源文件中的所有行,而可执行代码行数近似可执行行的数量。
现在我们已经理解了度量,让我们深入了解如何通过 Visual Studio 使用它们。
在 Visual Studio 2022 中使用代码度量
Visual Studio 2022 提供了一套强大的工具用于分析代码度量。以下是两种使用它们的方法:
- 在顶部菜单栏中选择分析 | 计算代码度量,并选择您是否要在特定项目或解决方案上计算度量。

图 3.16 – 从顶部菜单计算代码度量
- 或者,您可以直接在想要测量的解决方案或项目上右键单击,然后从上下文菜单中选择分析和代码清理 | 计算 代码度量

图 3.17 – 为项目计算代码度量
分析完成后,将打开一个窗口显示代码度量结果:

图 3.18 – 代码度量结果
在这里,我们可以查看诸如 循环复杂度、继承深度、类耦合、源代码行数 和 可执行代码行数 等度量。我们可以应用自定义过滤器,将度量结果限制在最小值和最大值之间。此外,为了更好地处理数据,我们可以将代码度量结果导出到 Excel 文件中。
理解和利用代码度量对于维护高质量的软件至关重要。Visual Studio 2022 提供了强大的工具来分析代码度量,帮助开发者识别和解决与安全和可维护性相关的问题。通过关注这些方面,开发者可以确保他们的代码库保持稳健、安全且易于管理。
在本节中,我们已导航到识别需要改进的代码部分的工具,并使用 IntelliCode 进行重构。在最后一节中,让我们深入了解重构的实际用例。
重构案例研究
重构涉及在不影响代码初始功能的情况下重构代码。目标是通过对代码进行增量修改来增强内部结构,而不影响代码的外部行为。为了检查代码的完整性,我们使用单元测试(参见本书的第一章)。重构是测试驱动设计过程的最后一步。
本节展示了一段包含不良实践的代码片段。我们将看到如何借助 Visual Studio 高效地修复这些问题。请记住,规范和实践必须与所有团队讨论,并且可能因团队而异。
处理常见的不良实践
这里有一段具有不良命名和可以轻松简化的条件检查的代码:
public static bool canregister(int age)
{
if(age > 18)
{
return true;
}
else
{
return false;
}
}
我们将使用 灯泡 来修复由实时代码分析器提供的命名违规(IDE1006):

图 3.19 – 修复命名违规
之后,我们可以使用 灯泡 简化年龄检查:

图 3.20 – 简化年龄检查
我们可以看到,预览更改窗口允许我们在解决方案的不同级别中更积极地修复所有出现的问题。
接下来,由于我们的方法只包含 return,我们可以通过将其转换为 表达式体(定义方法体的简洁方式)来提高可读性。我们将使用 螺丝刀 来完成这项工作:

图 3.21 – 使用表达式体
最后一个需要处理的不良实践是使用魔法数字。魔法数字指的是在源代码中直接出现的没有解释其意义或目的的数值字面量。没有适当的上下文,它可能很难更改或理解。因此,我们将引入一个具有可读性名称的常量来解释这个数字的目的。我们还将再次使用 灯泡 来完成这个任务:

图 3.22 – 引入一个常量
现在我们得到了一个简单的表达式主体,名字起得很好,并且遵循了清洁代码实践。
生成一个接口
例如,假设我们得到一个 AirTraffic 类,它有一个 RegisterAircraft 方法。现在为了给我们的代码添加抽象,我们想要创建一个 IAirTraffic 接口。我们将使用 螺丝刀 无缝地提取接口。

图 3.23 – 提取一个接口
这将打开一个窗口,其中包含选项,允许我们选择接口的配置。我们将保留默认选择,在新的文件中创建接口,命名为 IairTraffic.cs。
现在,我们正在添加一个新的方法,SendMessage,我们希望它也属于接口。再次,我们可以使用 螺丝刀 将新方法提升到接口:

图 3.24 – 将方法提升到接口
这种重构确保了所有实现 IAirTraffic 的类都将能够访问 SendMessage 方法,促进了接口和代码的重用的一致性。
文件作用域我们的命名空间
在 C# 10 中引入的 文件作用域命名空间 功能提供了一种更简洁的声明命名空间的方法。它消除了包围命名空间主体的花括号的需要,简化了语法并提高了可读性。
默认情况下,当我们创建 Visual Studio 中的类时,它使用较旧的命名空间版本,该版本使用花括号包围整个文件的内容。我们可以在命名空间的声明末尾添加一个分号,Visual Studio 将自动理解你想要将其转换为文件作用域命名空间。
为了避免这种重复操作,我们可以通过使用顶部的菜单栏将文件作用域命名空间设置为 Visual Studio 的默认值:选择 工具 | 选项 | 文本编辑器 | C# | 代码样式 | 常规 并将命名空间声明值更改为 文件作用域:

图 3.25 – 使命名空间声明为文件作用域
如果我们在团队中工作,我们可以通过点击 从设置生成 .editor 文件 选项直接为 选项 窗口生成 .editorconfig 文件,如图 图 3 .25 所示。
如果我们已经有了一个 .editorconfig 文件(可能是手动创建的,或者通过更改严重性级别生成的,如本章中 利用静态代码分析进行质量保证和安全 部分所示),我们可以添加以下行来设置命名空间声明为 file_scoped :
csharp_style_namespace_declarations = file_scoped
如果我们希望 Visual Studio 在未使用文件作用域命名空间时触发编译时错误,语法如下:
csharp_style_namespace_declarations = file_scoped:error
这使得我们可以将配置提交到我们的 Git 仓库,确保它与我们的团队共享。
摘要
在本章中,我们探讨了 Visual Studio 2022 中 Roslyn 的内部工作原理,使开发者能够充分利用其功能。通过掌握静态代码分析,我们可以通过精细控制严重性级别以及生成 .editorconfig 文件并将其传播到我们的团队,来增强项目中的质量保证和安全措施。
我们看到了 IntelliCode 如何重新定义生产力,通过整行自动完成和无缝访问 GitHub 文档提供预测性编码。
我们导航了代码的可维护性和安全性指标,这些指标为我们提供了宝贵的见解,使我们能够评估和改进代码库。凭借 Visual Studio 2022 的内置工具,项目可以优化以实现长期可持续性和健壮性。
我们以实际重构案例研究结束了本章,解决了一些常见陷阱,并展示了接口生成和命名空间细化等技术。通过分析现实场景,我们在应用高级重构原则方面获得了实践经验。
在下一章中,我们将探讨识别性能瓶颈、优化代码执行以及利用 Visual Studio 2022 的分析工具以确保应用程序性能达到顶峰的策略。
第四章:性能优化和性能分析
在本章中,我们深入探讨确保我们的代码不仅正确运行,而且运行高效的至关重要的方面。虽然编写能够工作的代码是必要的,但优化其性能同样重要,尤其是在当今快节奏的数字环境中,用户期望快速响应的应用程序。
在前几章中,我们通过掌握单元测试、测试驱动开发(TDD)、高级调试策略和代码分析,打下了基础。现在,我们将焦点转向 Visual Studio 2022 中可用的优化和性能分析工具,以便我们能够对应用程序进行微调,以实现最佳性能。
在本章中,我们将探讨各种旨在提高软件速度、响应性和资源效率的技术和方法。我们将从介绍性能优化的基础和利用性能分析工具来识别瓶颈和改进区域的重要性开始。
本章涵盖的关键主题包括以下内容:
-
性能优化简介
-
利用 Visual Studio 性能分析工具
-
分析 CPU 使用情况
-
内存性能分析和优化
-
优化数据库交互
通过掌握这些概念和技术,我们将学习如何定位性能问题,优化代码库的关键部分,并确保我们的应用程序在各种工作负载和条件下提供无缝的用户体验。
让我们共同踏上构建更快、更高效软件的旅程。
技术要求
在编写本章时,我使用了以下版本的 Visual Studio:
-
Visual Studio Enterprise 2022 版本 17.12.0
-
预览 1.0
本章的代码文件可以在github.com/PacktPublishing/Mastering-Visual-Studio-2022/tree/main/ch04找到。
性能优化简介
软件开发中的性能优化涉及对应用程序进行精炼,使其以最大效率运行,最小化资源消耗,如内存、CPU 和带宽。这个过程包括分析各个开发阶段的表现,通常在产品稳定版本确立后,会着重提高效率。
我们性能优化过程中的主要步骤是识别瓶颈,因为这使我们能够确定代码中导致性能问题的具体区域。瓶颈是代码中执行速度显著减慢的点,通常是由于资源限制或效率低下的算法。通过识别这些瓶颈,我们可以将优化努力集中在最能产生影响的领域,从而实现更高效、更快的应用程序。这种有针对性的方法不仅提高了应用程序的性能,还通过减少加载时间和提高响应速度来增强整体用户体验。此外,在开发早期阶段识别瓶颈可以防止昂贵的返工和延误,因为在问题根深蒂固于我们应用程序的架构之前解决性能问题更为经济。本质上,识别和解决瓶颈的能力是我们作为开发者创造高性能应用程序的关键技能,确保我们的软件运行顺畅且高效。
性能优化可以在不同的层面上进行,并提供了不同的探索路径:
-
在设计层面,系统的架构在其性能中起着至关重要的作用。以性能为导向的设计涉及对系统如何与硬件和网络资源交互做出战略决策。例如,通过最小化网络请求可以降低网络延迟,理想情况下是一次请求而不是多次。这种方法不仅减少了网络负载,还简化了应用程序的架构,使其更容易维护和扩展。
-
源代码中的实现选择也对系统优化有重大影响。采用高效的编码实践对于实现系统优化至关重要。这包括避免不必要的计算,这可以显著减少应用程序的计算开销。例如,使用语言集成查询(LINQ)进行数据处理可以生成比传统循环更易读且可能更高效的代码。此外,利用 C#的异步编程功能,如 async 和 await,可以通过允许应用程序在等待长时间运行的操作完成时执行其他任务来提高应用程序的响应速度。
-
算法和数据结构的选择是系统性能的关键因素。高效的算法和数据结构可以显著降低操作的时间复杂度,使系统能够轻松处理更大的数据集和更复杂的任务。理想情况下,算法应该以常数(O(1))、对数(O(log n))、线性(O(n))或对数线性(O(n log n))的时间复杂度运行。具有二次复杂度(O(n²))的算法在数据集规模增长时可能难以高效扩展。同样,封装数据和操作的抽象数据类型,与更复杂的数据结构相比,可能对系统优化更有效。
-
在构建级别进行优化涉及在构建过程中做出决策,这些决策可以使应用程序针对特定的处理器模型或环境进行定制。这可能包括禁用不必要的软件功能,从而减小可执行文件的大小并提高其性能。此外,构建级别的优化可能涉及使用编译器标志启用特定的优化,例如循环展开或函数内联,这可以提高生成代码的效率。
你可能已经注意到,我使用 Big O 表示法根据复杂度对算法进行了分类;让我们回顾一下这个表示法。
Big O 表示法是一种数学表示,用于描述算法的性能或复杂度,特别是关于它们随着输入大小增加的运行时行为。
理解 Big O 表示法对于软件工程师来说非常重要。它使我们能够评估和对比不同算法的效率。因此,我们可以就选择适合特定场景的算法做出明智的决定。
以下要点概述了著名的 Big O 表示法:
-
常数时间 O(1):无论输入数据如何,执行时间保持不变
-
对数时间 O(log n):对于输入数据的每次加倍,复杂度增加一个单位
-
线性时间 O(n):执行时间随着输入数据大小的增加而线性增长
-
对数线性时间 O(n log n):复杂度随着线性和对数的组合增长
-
二次时间 O(n²):所需时间与元素数量的平方成正比
-
立方时间 O(n³):所需时间与元素数量的立方成正比
-
指数时间 O(2^n):每增加一个新元素,时间翻倍
-
阶乘时间 O(n!):复杂度根据数据集的大小以阶乘方式增长
既然我们已经探讨了软件开发中性能优化的基本原理,让我们深入了解识别和解决性能问题的实际方法。在我们的努力中,Visual Studio 性能分析工具是一套宝贵的工具。通过利用这些工具的功能,我们可以更深入地了解应用程序的性能,并简化优化过程。让我们看看如何有效地利用 Visual Studio 性能分析工具来提高我们的软件应用程序的性能。
利用 Visual Studio 性能分析工具
Visual Studio 性能分析工具是一套集成到 Visual Studio 中的性能测量和诊断工具。在本节中,我们将探讨如何使用它,并探索提供的工具以探索和监控我们的应用程序。
要打开性能分析器,我们前往 调试 | 性能分析器 或按 Alt + F2。

图 4.1 – 性能分析器
在点击 开始 按钮之前,让我们回顾性能分析器功能提供的各种选项,以便对应用程序进行性能分析。
分析 .NET 异步事件
.NET 的异步和 await 功能允许我们分析按时间顺序组织的事件,以表格形式显示活动发生时的开始时间、结束时间和持续时间。任务在 名称 列中标出。

图 4.2 – .NET 异步
如果在收集会话期间任务未完成,结束时间列将出现一个 不完整 标签。
要调查特定的任务或活动,我们可以右键单击该行并选择 转到源文件,以查看该活动发生在我们代码的哪个位置。
理解异步性能的特征至关重要。虽然异步方法旨在提高应用程序的响应性和可伸缩性,但它们确实由于编译器创建的状态机而引入了一些开销。然而,这种开销通常很小,对于高吞吐量场景来说效率很高。
当比较异步代码与同步代码的性能时,我们需要考虑所执行操作的性质。对于本质上异步的操作(如 输入/输出 ( I/O )-bound 操作),异步方法可以通过在等待时释放线程来处理其他请求,从而提供显著的性能优势。然而,对于 CPU-bound 操作,异步和同步方法之间的性能差异可能微不足道。
为了有效地使用 .NET 的异步和等待功能监控我们的应用程序性能,我们可以利用 Visual Studio 中的 .NET 异步 工具进行异步代码执行的详细分析。此外,像 Stackify Retrace 这样的外部工具为 .NET 应用程序提供全面的监控能力,包括对异步/等待的支持。了解异步方法的表现特性和执行操作的本质对于做出何时采用异步编程模式的明智决策至关重要。
使用 .NET 计数器进行监控
Visual Studio 2022 集成了 .NET Counters 工具,这是一个高级功能,允许我们像我们这样的开发者直接在 Visual Studio 分析器中可视化性能计数器随时间的变化。此工具证明对于监控和分析 .NET 应用程序的各种指标(如 CPU 使用率、垃圾收集器堆大小以及我们可能在应用程序中实现的任何自定义计数器)特别有用。这种集成使我们能够直接从 Visual Studio 环境中利用 .NET Counters 的功能,为性能监控和分析提供更流畅和集成的体验。
Visual Studio 2022 增强了 .NET 计数器工具以支持两个创新指标:UpDownCounter 和 ObservableCounter。UpDownCounter 允许实时跟踪具有递增和递减变化的值,这对于监控如网络应用程序中的用户交互等动态值非常理想。另一方面,ObservableCounter 自动管理聚合总数,提供可定制的回调委托以实现精确控制。此功能可以通过有效管理活动会话总数来特别有用,从而优化服务器资源。
此外,工具中的过滤器弹出功能使我们能够方便地根据标签过滤数据点。此动态调整功能显著增强了我们在项目中监控动态值的灵活性和流程化。
在收集数据时,我们可以看到 .NET 计数器的实时值,并同时查看多个计数器的图表。

图 4.3 – .NET 计数器
一旦我们停止收集,我们就会得到一份详细的报告,显示所选时间范围内每个计数器的最小值、最大值和平均值。这份报告为我们提供了应用程序性能指标的综合概述,帮助我们更有效地识别和解决性能瓶颈。
跟踪 .NET 对象分配
.NET 对象分配跟踪 工具对于理解 .NET 代码中的分配模式以及通过识别最占用内存的方法来优化应用程序的内存使用非常有价值。然而,需要注意的是,虽然此工具可以揭示对象分配的位置,但它并不能阐明对象为何保留在内存中。
我们通过点击开始按钮来启动工具,如果我们在开始分析器之前希望数据收集暂停,工具会提供开始时收集暂停选项。

图 4.4 – 开始分析
这允许我们通过在诊断会话视图中点击记录按钮手动开始数据收集。
执行工具后,我们可以停止收集数据或关闭我们的应用程序以审查数据。该工具提供了全面的内存分配数据,包括分配内存的对象的位置以及这些对象分配的内存量。它还显示了在特定分配类型或函数中占用内存的对象数量,以及消耗的内存量而不是对象数量。
此外,该工具还提供了一个收集视图,展示了在垃圾回收期间收集或保留的对象数量,为我们提供了有关垃圾回收事件(如垃圾回收类型、事件原因以及垃圾回收器执行后大对象堆(LOH)和固定对象堆(POH)的大小)的见解。
查看事件
事件查看器工具允许我们在应用程序停止后检查收集到的信息,就像尸检分析一样。它显示了一个事件列表,如模块加载、线程启动和系统配置,有助于在 Visual Studio 分析器中诊断我们的应用程序性能。
要启用自定义Windows 事件跟踪(ETW)事件,我们可以使用自定义事件对代码进行操作,并配置它们在事件查看器中显示。这涉及到设置提供程序名称和 GUID 以用于我们的自定义事件代码。对于 C#自定义事件代码,我们设置与声明事件代码时相同的提供程序名称值,而对于本地自定义事件代码,我们根据自定义事件代码的 GUID 设置提供程序 GUID。一旦配置完成,这些自定义事件将在我们收集诊断跟踪时在事件查看器中显示。
事件查看器一次可以显示多达 20,000 个事件。为了关注特定事件,我们可以通过选择事件过滤器来过滤显示。此外,我们还可以看到每个提供程序发生的总事件数的百分比,提供了我们时间花费的细分。这种过滤和细分有助于识别分析中最相关的事件。
例如,要启用自定义 ETW 事件:
-
首先,构建我们的自定义事件代码。
-
然后,在性能分析器窗口(通过Alt + F2访问),启用事件查看器并选择其旁边的设置图标。
-
在对话框中,启用附加提供程序下的第一行,并根据我们的自定义事件代码进行配置。
-
对于本机自定义事件代码,我们设置提供者 GUID值,并将提供者名称值留空或使用其默认值。
-
对于 C#的自定义事件代码,我们在声明事件代码时设置了相同的提供者名称值,并将提供者 GUID留空。配置完成后,当我们收集诊断跟踪时,我们的自定义事件将出现在事件查看器中。
对于我们这些希望诊断性能问题或详细了解应用程序行为的开发者来说,此工具特别有用。它为我们应用程序的活动和性能指标提供了一个全面的视图。
分析文件 I/O
Visual Studio 中的文件 I/O工具是一个强大的分析工具,旨在帮助我们优化文件 I/O 操作,从而提高我们应用程序的性能。此工具特别适用于诊断缓慢的加载时间和低效的数据读取或写入模式。它提供了在分析会话期间关于文件读取和写入操作的详细信息,包括访问的文件、每个文件的目标进程以及每个文件的汇总信息。该工具还提供诸如重复因子等功能,帮助我们确定是否读取或写入比必要更多的数据,这表明了潜在的优化区域,例如缓存文件读取的结果。
文件 I/O 工具提供了在分析会话期间读取的文件读取和写入信息。收集后,文件会自动生成在报告中,并按其目标进程排列,显示汇总信息。如果我们右键单击其中一行,我们可以进入代码中的源。如果一个汇总行被读取多次,我们可以展开它以查看该文件的个别读取操作及其频率,如果它们被多次读取。
分析数据库性能
Visual Studio 中的数据库分析器工具是一个旨在帮助我们开发者诊断和优化应用程序中数据库操作性能的功能。它对于使用 ADO.NET 或 Entity Framework Core 的.NET Core 应用程序特别有用,提供了关于数据库活动(如查询执行时间、使用的连接字符串以及这些查询在代码中的位置)的见解。此工具是 Visual Studio 中的性能分析器的一部分,自 Visual Studio 2019 版本 16.3 以来一直可用。
一旦我们开始分析会话,我们就像平时一样与我们的应用程序交互,执行我们怀疑可能引起数据库性能问题的操作。完成我们的操作后,我们在 Visual Studio 中停止收集。然后,该工具处理收集到的数据,并显示在我们分析会话期间发生的查询表,以及显示这些查询的时序和频率的图表。这些信息可以帮助我们识别长时间运行的查询、低效的连接字符串或数据库操作中的其他性能瓶颈。
此外,数据库分析工具支持分析使用 dotnet trace 收集的跟踪,允许我们从.NET Core 运行的任何地方收集数据,包括 Linux,并在 Visual Studio 中进行分析。这个特性特别适用于诊断在没有安装 Visual Studio 的环境中或用于脚本化性能跟踪收集的环境中的性能问题。
总结来说,Visual Studio 中的数据库分析工具是我们这些与数据库交互的.NET Core 应用程序的开发者强大的诊断工具。它提供了对数据库操作的详细洞察,帮助我们更有效地识别和解决性能问题。
仪器化我们的.NET 应用程序
在 Visual Studio 中,我们使用仪器工具来收集精确的调用次数和调用时间,这对于性能分析和优化至关重要。有两种主要的仪器方法可用:
-
静态仪器:这种方法涉及在程序运行之前修改程序的文件。我们使用名为 VSInstr 的工具将仪器代码插入到应用程序的二进制文件中。静态仪器对于收集详细的时序数据非常有效,但由于文件修改可能会破坏强名称签名。它还要求文件以特定的顺序部署,这对于复杂的程序来说可能很麻烦。
-
动态仪器:在 Visual Studio 2022 版本 17.5 中引入,这种方法不会修改程序的文件。相反,它将文件加载到内存中并在运行时修改它们以收集仪器信息。动态仪器提供了更准确的信息,特别是对于程序的小部分,并允许调查特定的代码部分。由于仪器在运行时发生,因此避免了破坏强名称签名的问题。这种方法简化了查找和仪器文件的过程,尤其是在复杂的程序中。
这个工具类似于 CPU 使用工具,但专注于墙钟时间而不是 CPU 利用率,这使得它在理解函数执行时间至关重要的场景中适用。
通过使用上述工具,我们可以收集关于我们应用程序性能的宝贵见解。
然而,为了确保性能测量的最佳准确性,建议我们在发布模式下而不是调试模式下分析我们的应用程序。调试构建可能会引入额外的开销,从而可能歪曲我们的结果。
当我们在分析过程中需要检查变量值或使用断点时,我们应该考虑利用诊断工具窗口中找到的集成调试工具。这些工具针对此类任务进行了定制,可能为我们提供更适合的分析环境。
为了全面了解我们应用程序的性能,我们可以利用 Visual Studio 同时利用多个分析工具的能力。这种方法允许我们从不同的角度检查应用程序的性能,提供更全面的分析。
你可能已经注意到,我遗漏了 Profiler 性能工具提供的三个工具。我将在下一节中突出它们,首先是 CPU 使用情况分析器。
分析 CPU 使用情况
Visual Studio 中的CPU 使用情况工具旨在帮助我们识别应用程序中的高 CPU 利用率和其他相关性能问题。它可以用于本地跟踪会话和生产环境,提供有关可能需要优化的地方的洞察。要使用 CPU 使用情况工具而不使用调试器,我们应该将解决方案配置设置为发布,并将部署目标选择为本地 Windows 调试器(或本地计算机)。在可用工具下,我们选择CPU 使用情况,然后选择启动。
如果我们启用“启动时收集暂停”选项,数据收集将不会开始,直到我们在诊断会话视图中选择记录按钮。应用启动后,诊断会话开始,显示 CPU 使用数据。收集完数据后,我们选择停止收集。然后工具分析数据并显示报告,可以过滤和搜索特定线程或节点。
CPU 使用情况工具特别适用于诊断我们代码库中的性能问题,识别瓶颈,并理解 CPU 使用模式。它提供自动洞察和多种数据视图,使我们能够有效地分析和诊断性能问题。此工具在生产环境中很有益,但目前难以调试,但可以使用此工具捕获和分析数据,以了解潜在原因并提出修复建议。
CPU 使用情况工具特别适用于诊断减速、进程挂起以及识别代码库中的瓶颈,使其成为优化应用程序性能的必备工具。
当运行此分析工具时,它会检测每秒的 CPU 使用情况并收集跟踪信息,生成一个包含图表的报告以可视化 CPU 使用的峰值和谷值。
当我们首次启动 CPU 使用率工具时,它将每秒收集大量数据以分析应用程序中的情况,默认设置为1000样本/秒。
我们可以通过点击配置控制台CPU 使用率标签右侧的齿轮,在点击开始按钮之前,来个性化设置每秒收集样本的数量(图 4.1)。根据我们的需求,我们可以调整结果的准确性和数据收集时间。

图 4.5 – CPU 使用率设置
当我们停止收集或关闭我们的应用程序时,CPU 使用率工具会生成报告。最初,我们会进入摘要页面,该页面显示泳道图、顶级函数部分和热点路径部分。

图 4.6 – 摘要页面
在这里,我们可以通过右键单击并拖动图形来包围我们想要关注的峰值,从而缩小潜在的瓶颈。通过这样做,我们实际上通过时间过滤了图形。
通过点击打开详细信息…链接,我们可以深入了解其他五个视图:
-
调用者/被调用者
-
调用树
-
模块
-
函数
-
火焰图
让我们详细了解每个部分:
- 在调用者/被调用者视图中,我们可以观察所选函数与其被调用的函数(调用函数)以及它调用的函数(被调用函数)之间的关系。它提供了关于所选函数所花费的总时间和其在整个应用程序运行时间中所占百分比的见解。此外,它还提供了关于仅在函数体中花费的时间(函数体)的信息。此视图有助于我们了解函数对应用程序性能的影响并识别潜在的瓶颈。

图 4.7 – 调用者/被调用者
- 调用树视图展示了我们应用程序中函数调用的层次结构表示,从顶级伪节点开始。它包括系统和框架代码(在[外部代码]节点下)以及用户代码方法。

图 4.8 – 调用树视图
此视图有助于了解函数调用的顺序和嵌套,有助于识别应用程序中最占用 CPU 的路径。
- 在模块视图中,我们可以看到包含函数的模块列表,这在分析外部代码时特别有用。

图 4.9 – 模块视图
它帮助我们了解哪些模块对 CPU 使用率贡献最大,有助于识别可能影响性能的第三方库或系统组件。
- 函数视图列出了我们应用程序中的所有函数,按其 CPU 使用率排序。它提供了详细的信息,例如总 CPU(函数及其调用的任何函数所花费的时间)和自 CPU(仅在函数体中花费的时间)。

图 4.10 – 函数视图
这种视图对于识别我们应用程序中最资源密集型的功能并集中优化努力至关重要。
- 火焰图是一种表示我们应用程序随时间推移的调用栈的可视化。它有助于识别热点路径,即消耗大量 CPU 时间的函数调用序列。图中每个函数的宽度对应于它消耗的 CPU 时间,这使得更容易发现性能瓶颈。火焰图视图特别有助于理解我们应用程序的整体 CPU 使用模式,并确定优化的具体区域。

图 4.11 – 火焰图
我们可以通过使用翻转火焰图选项并放大我们的兴趣点来根据我们的偏好翻转视图。
对于调试会话,可以通过诊断工具窗口访问 CPU 使用率工具,该窗口默认自动出现,除非已关闭。我们可以通过工具栏上的选择工具设置选择是否查看CPU 使用率、内存使用率或两者,工具默认启用以进行 CPU 利用率分析。
当调试器暂停时,诊断工具窗口中的 CPU 使用率工具会收集关于我们应用程序中正在执行的功能的信息,列出执行工作的功能,并提供一个时间线图,以便关注采样会话的特定部分。
虽然 CPU 使用率和内存使用率相关,但它们之间没有直接相关性。一个对另一个的影响取决于系统上运行的应用程序所执行的具体任务。监控这两个指标对于优化系统性能和有效管理能耗至关重要。
现在我们已经探讨了如何分析 CPU 使用率,让我们继续我们的旅程,通过监控内存分配来继续前进。
内存分析和优化
提醒一下,当计算机程序错误处理内存分配时,就会发生内存泄漏,导致不再需要的未释放内存。由于自动垃圾回收和.NET 应用程序是用托管代码编写的,因此.NET 应用程序通常不太容易发生内存泄漏。这意味着运行时控制内存分配和释放。然而,如果我们编写有问题的代码或误用可处置模式,内存泄漏仍然可能发生。
在本节中,我们将探讨如何利用 Visual Studio 通过使用内存使用率分析工具和调试期间可用的诊断工具来解决内存泄漏。
使用内存使用工具
要找到和解决内存泄漏,我们可以使用 Visual Studio 中的内存使用工具。这是一个强大的分析功能,旨在有效地监控和分析应用程序的内存使用情况。它支持各种应用程序类型,包括.NET、ASP.NET、C++和混合模式应用程序。这个多功能的工具可以在有和没有调试器的情况下使用,满足不同的开发场景。其关键优势之一在于其识别内存泄漏和低效内存使用模式的能力。
在我们的诊断会话期间,内存使用工具提供了一个时间线图,显示了应用程序运行时的内存波动。这种图形表示有助于确定代码中可能收集或生成数据低效的区域,这可能导致内存泄漏或过度使用内存。

图 4.12 – 内存使用图
我们可以使用这个工具在不同的时间间隔内详细记录应用程序的内存状态快照。然后,我们可以将这些快照进行比较,以确定内存问题的根本原因。它们展示了关键指标,如内存中对象和字节数的总数,以及连续快照之间的差异。

图 4.13 – 内存使用报告类型
我们可以通过详细的内存使用报告视图深入了解这些快照,了解每个快照中存在的类型和实例,或两个快照之间的差异。
一旦停止数据收集,内存使用工具将显示一个包含内存使用数据的概览页面。这个概览有助于我们了解应用程序的内存影响,并找出可能从优化中受益的区域。
对于更高级的分析,内存使用工具提供了对各种内存问题的洞察,如重复字符串、稀疏数组和事件处理器泄漏,特别是对于托管内存分析非常有用。

图 4.14 – 内存使用报告洞察
利用这些洞察,我们可以更有效地识别和解决常见的内存问题。
有些场景可能需要我们专注于深入挖掘代码库的某个特定部分,为此,我们可以使用调试模式下的诊断工具。
在调试时探索内存使用情况
对于这部分,我将创建一个小的控制台应用程序,您可以在 GitHub 上检索。以下代码包含一个while循环,该循环将一个字符串列表填充为一个大随机字符串:
List<string> list = new();
while (true)
{
list.Add(GenRandomStr(10000));
Thread.Sleep(1);
}
static string GenRandomStr(int length)
{
Random rnd = new();
var chars = new List<char>();
for (var i = 0; i < length; i++)
{
var a = (char)rnd.Next(65, 122);
chars.Add(a);
}
return string.Concat(chars);
}
在前面的代码块中,我们首先在我们的应用程序中设置断点,我们怀疑内存泄漏可能发生的地方。这可能是在函数的开始或我们怀疑导致内存泄漏的代码区域。
对于这个示例,由于代码简单,我们将在循环的闭合括号处设置断点。
此外,在更复杂的场景中,我们可以利用其他分析工具来识别代码库中的可疑位置。
接下来,我们将使用 诊断工具,默认情况下,它会在调试器启动时打开。如果没有,您可以通过导航到顶部菜单并点击 调试 | 窗口 | 显示 诊断工具 来访问它。

图 4.15 – 诊断工具
在 诊断工具 窗口中,我们检索 事件、进程内存 和 CPU 使用图表。在我们的示例中,我们将观察 进程内存 部分,其中内存使用量随着循环迭代而增加。此外,我们还可以监控垃圾收集器的工作,以评估其对内存分配的影响。
要分析堆栈,我们可以使用 获取快照 选项进行快照。此操作将生成不同时间间隔的内存状态报告,正如我们在之前的分析工具描述中观察到的。

图 4.16 – 内存使用快照
在 图 4.16 中,我们可以观察到在快照之间,堆大小 和 对象 的数量危险地增加。这表明分配不当,换句话说,就是内存泄漏。
我们可以通过点击 查看堆 选项来深入了解,通过大小和数量探索 对象类型。

图 4.17 – 内存使用
在这里,我们可以看到我们的内存泄漏原因是 List
虽然 CPU 和内存可以提供对我们应用程序性能的洞察,但软件中观察到的大多数延迟都来自数据库交互,在下一节中,我们将看到如何优化它们。
优化数据库交互
Visual Studio 2022 引入了一个名为 数据库分析器 的新分析工具。它允许我们探索应用程序中的数据库交互。
在本节中,我们将探讨如何使用数据库分析器工具以及它们如何帮助我们识别代码库中的查询优化机会。
要打开它,我们通过 性能分析器 选择 数据库,在那里我们可以将其与 CPU 使用 结合以获得更多信息。

图 4.18 – 选择数据库和 CPU 使用工具
当我们点击 启动 按钮,分析器将启动我们的应用程序并开始收集数据。在此期间,我们可以在应用程序上执行长时间运行的操作,以确定延迟的根本原因。
在点击 停止收集 按钮后,我们将启动报告的生成。

图 4.19 – 数据库报告
数据库报告将显示一个包含已执行查询信息的表格;默认情况下,它显示以下信息的列:
-
查询的开始时间
-
查询的 SQL 代码
-
执行持续时间
-
受影响的记录数
-
读取的记录数
在更大的应用程序中,我们可以集成多个数据库,例如在利用命令查询责任分离(CQRS)模式以及数据库复制时。为了帮助我们的调查,我们可以通过右键单击显示的列并检查我们需要哪一个来显示另外三个列。

图 4.20 – 数据库报告管理列
附加的列如下:
-
数据库
-
连接字符串
-
查询源显示所使用的数据提供程序(EFCore、Dapper、ADO.NET 或其他)
结合 CPU 使用工具,我们可以轻松地聚焦于消耗周期,以检查在此时间内的查询启动。

图 4.21 – 数据库报告时间筛选
当我们识别到一个可能因其长事务持续时间或大量相关查询而引起我们注意的查询时,我们可以进行调查。
最后,在查询列表中,我们可以通过右键单击我们感兴趣的行并选择转到****源文件,轻松地跳入代码源进行进一步调查或甚至重构。

图 4.22 – 转到源文件
Visual Studio 性能分析工具的强大之处在于能够结合其一些工具进行综合调查。我的建议是利用本章中突出显示的三个工具:内存使用、CPU 使用和数据库工具。这将帮助我们快速识别诸如生成过多内存分配和 CPU 利用率的查询等问题,尤其是在使用对象关系映射(ORMs),如 EF Core 或 Dapper,需要实例化对象以运行查询时。
摘要
本章提供了利用 Visual Studio 性能分析工具来帮助我们调查和优化性能瓶颈的关键见解,从而提高了应用程序的性能。
在本章中,我们涵盖了一系列主题,从理解性能优化的基础知识到有效地利用 Visual Studio 的性能分析工具。我们学习了如何分析 CPU 使用情况并识别内存和数据库瓶颈,以识别和优化关键部分和我们的代码库,以改善性能。
在我们结束本章时,我们标志着掌握核心开发技能旅程的第一部分的结束。从单元测试和 TDD 到高级调试策略、代码分析和现在性能优化与剖析,你已经为你的开发旅程奠定了坚实的基础。
在接下来的章节中,我们将继续拓展我们的视野,深入探讨高级主题,如多平台应用 UI 开发、高级 Web 开发工具、机器学习集成以及高级云集成和服务。
开始第二部分,我们将通过探索 Visual Studio 为 MAUI 提供的工具,深入跨平台开发的世界。
第二部分:拓展开发视野
在本第二部分中,我们专注于通过利用 Visual Studio 的高级技术来扩展您的开发专业知识,构建多功能应用程序。从多平台应用 UI 开发到高级 Web 工具,再到机器学习集成和云服务,这些章节为您提供了构建现代、可扩展和智能应用程序的技能,推动您开发能力的边界。
本部分包含以下章节:
-
第五章 ,多平台应用 UI 开发
-
第六章 ,高级 Web 开发工具
-
第七章 ,机器学习集成
-
第八章 ,高级云集成和服务
第五章:多平台应用 UI 开发
本章深入探讨了使用 Visual Studio 2022 进行跨平台开发,重点关注.NET MAUI(多平台应用 UI)。我们将全面了解如何使用.NET MAUI 构建在多个平台上无缝运行的应用程序。主题包括.NET MAUI 的介绍、探索高效开发的基本工具、在多种设备上的调试以及从 Xamarin 迁移到.NET MAUI 的实用指南。
在本章中,我们将探讨以下内容:
-
MAUI 简介
-
探索 MAUI 的工具
-
设备调试
-
从 Xamarin 迁移
到本章结束时,我们将能够高效且有趣地构建引人入胜的多平台应用程序。
那么,让我们共同踏上掌握 Visual Studio 进行 MAUI 开发的旅程吧。
技术要求
在编写本章时,我使用了以下版本的 Visual Studio:
-
Visual Studio Enterprise 2022 版本 17.12.0
-
预览版 1.0
本章的代码文件可以在以下 GitHub 仓库找到:github.com/PacktPublishing/Mastering-Visual-Studio-2022/tree/main/ch05。
要访问本章中的 WordPuzzle 项目,请查看以下 GitHub 仓库:github.com/dotnet/maui-samples/tree/main/8.0/Apps/WordPuzzle。
MAUI 简介
MAUI是一个多才多艺的框架,它使开发者能够使用 C#和 XAML 为移动和桌面平台创建原生应用。使用 MAUI,开发者可以从统一代码库针对 Android、iOS、macOS 和 Windows 设备。
这个开源框架建立在 Xamarin.Forms 的基础上,扩展其功能以覆盖桌面场景,同时旨在提高性能、灵活性和将应用逻辑和 UI 布局合并到一个代码库中的能力。
跨平台开发的演变
跨平台开发框架通过允许多平台代码共享而彻底改变了应用开发。例如,Xamarin.Forms 使公司能够共享超过 95%的代码库,最大化了开发投资。然而,这一领域已经发展,促使出现如 MAUI 这样的框架来解决之前的限制并适应应用开发的不断变化需求。
什么是 MAUI?
由微软开发的 MAUI 是一个开源框架,旨在通过单一代码库简化原生跨平台应用的开发。它建立在 Xamarin.Forms 的基础上,增加了额外的功能,例如统一的项目结构和灵活性。
通过利用.NET 6,MAUI 集成了.NET 框架的最新进展、性能增强和安全更新,使开发者能够利用.NET 库和工具的广泛生态系统来提升他们的应用程序。
MAUI 的关键特性
MAUI 的一些关键特性如下:
-
多平台单一代码库:MAUI 通过将代码、资源和 UI 元素合并到单一的项目结构中,简化了项目管理,减少了复杂性,并节省了时间
-
增强的性能和响应性:MAUI 针对性能改进而设计,确保在所有支持的平台上运行顺畅且高效
-
原生功能和控件支持:MAUI 优先考虑原生用户界面,在所有平台上提供无缝的用户体验
-
提高开发者生产力:如 XAML 和 CSS 的 Hot Reload 等特性,能够实时可视化 UI 更改,显著加速开发过程
现在我们已经探讨了.NET MAUI 的关键特性和架构,很明显,这个框架代表了在应用程序开发方面的一大飞跃。
MAUI 的架构
MAUI 采用一种策略,它利用每个平台的原生功能,同时保持单一的代码库。这种方法使开发者能够通过统一的 API 访问原生平台功能和 UI 控件,从而提供无妥协的用户体验,同时实现更高的代码重用。
.NET MAUI 为构建移动和桌面应用程序的用户界面提供了一个统一的框架。
图 5.1(来自learn.microsoft.com)的图表展示了.NET MAUI 应用程序的高级结构:

图 5.1 – MAUI 的高级结构(来源:learn.microsoft.com)
我们可以在 PC 或 Mac 上构建.NET MAUI 应用程序。在我们的.NET MAUI 应用程序中,我们的代码将主要与.NET MAUI API 交互。然后,.NET MAUI 随后直接访问原生平台 API。此外,当需要时,我们的应用程序代码可以直接与平台 API 交互。
最后,代码被编译成原生应用程序包:
-
.NET MAUI 通过将 C#编译成中间语言(IL)来促进 Android 应用程序的开发。在应用程序启动时,此 IL 代码随后被 JIT 编译成原生程序集。相比之下,使用.NET MAUI 开发的 iOS 应用程序在部署前直接从 C#编译成原生 ARM 汇编代码。
-
对于 macOS 应用程序,.NET MAUI 利用了苹果提供的 Mac Catalyst 功能。此功能允许使用 UIkit 构建的 iOS 应用程序在 macOS 平台上运行。此外,它还支持 AppKit 和必要的平台特定 API 的集成。
-
当涉及到 Windows 应用程序时,.NET MAUI 使用 Windows UI 3(WinUI 3)工具包。这种方法使得创建本地的 Windows 桌面应用程序成为可能。
现在我们已经了解了 MAUI 是什么,让我们深入了解 Visual Studio 为增强我们的 MAUI 体验提供的工具。
探索 MAUI 工具
在本节中,为了探索 Visual Studio 为 MAUI 提供的工具,我们将首先创建一个基本应用程序。通过构建此应用程序,我们将获得在 Visual Studio 为 MAUI 开发中可用的各种工具和功能的实际经验。这种实用方法将确保我们不仅理解这些工具的目的,而且学习如何有效地利用它们,从而提高我们的开发流程。
创建简单的 MAUI 应用程序
首先,我们必须确保我们安装了带有 MAUI 工作负载的最新版本的 Visual Studio 2022。如果您尚未安装,您可以从 Visual Studio 安装程序或使用以下命令更新您的 Visual Studio:
dotnet workload install maui
您还可以使用 Visual Studio 安装程序来安装 MAUI 工作负载或检查您拥有的版本是否为最新版本,通过启动您的 Visual Studio 安装程序并点击修改已安装的 Visual Studio 的按钮(见 图 5.2):

图 5.2 – 修改 Visual Studio 的工作负载
现在,我们已经准备就绪。我们可以按照以下步骤创建我们的新 MAUI 项目:
- 打开 Visual Studio 并创建一个新的项目。选择 MAUI 作为项目类型。

图 5.3 – .NET MAUI 应用模板
- 我们可以看到,MAUI 项目有一个针对多个平台的共享代码库。在 .NET MAUI 设置中,公共代码库位于共享项目中。相反,每个特定平台的项目的独特代码针对其相应环境进行了定制(例如,Platforms | Android,Platforms | iOS,Platform | Tizen,Platforms | MacCatalyst,以及 Platforms | Windows),如 图 5.4 所示:

图 5.4 – MAUI 文件夹架构
- 在 Shared 项目中,我们找到主页的 XAML 文件,位于 MainPage.xaml。这是我们设计应用程序 UI 的地方。
对于我们的示例,我们将简单地构建一个应用程序,其中包含一个按钮,点击后显示文本消息。
我们将首先设计 UI。为此,我们在 Shared 项目中打开 MainPage.xaml 并用以下 XAML 代码替换其内容:
<ContentPage xmlns=»http://schemas.microsoft.com/
dotnet/2021/maui»
xmlns:x=»http://schemas.microsoft.com/
winfx/2009/xaml»
x:Class="MyMauiApp.MainPage">
<StackLayout>
<Button x:Name="MyButton"
Text="Click Me"
Clicked="OnButtonClicked"/>
<Label x:Name="MessageLabel"
Text="Welcome to MAUI!"/>
</StackLayout>
</ContentPage>
这段 XAML 代码片段定义了我们 .NET MAUI 应用程序中 ContentPage 的基本结构。这个页面包含 StackLayout,这是一个简单的布局,它将子元素排列成一行,可以是水平或垂直方向。
然后,我们在Shared项目中打开MainPage.xaml.cs并添加以下 C#代码:
using Microsoft.Maui.Controls;
namespace MyMauiApp
{
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
}
private void OnButtonClicked(
object sender,
EventArgs e)
{
MessageLabel.Text = "You clicked the button!";
}
}
}
这是.NET MAUI 应用程序中MainPage类的 C#代码后置。此代码补充了您之前共享的 XAML 标记,定义了ContentPage的行为。具体来说,它包括OnButtonClicked方法的实现,该方法在按钮被点击时更新名为MessageLabel的标签的文本。
最后,我们可以运行应用程序。启动按钮允许我们选择模拟器或设备作为目标(见图 5.5):

图 5.5 – 启动 Android 模拟器
例如,我们可以选择Android 模拟器;当我们第一次启动它时,Visual Studio 将提示我们使用向导进行安装。
现在,当我们启动我们的应用程序时,我们将看到一个标签为点击我的按钮(见图 5.6)。

图 5.6 – Android 模拟器
当我们点击按钮时,其下方的文本会变为您点击了按钮!。
这是一个基本示例,帮助我们开始使用 MAUI。现在我们有一个正在运行的应用程序,我们可以探索 Visual Studio 提供的所有工具,以增强我们的 MAUI 开发体验。
接下来,让我们探索 XAML 实时预览以利用即时 UI 修改。
XAML 实时预览
当使用 Windows 机器可执行文件时,Visual Studio 中的XAML 实时预览功能允许开发者无需手动保存或重新构建项目即可看到 XAML UI 更改的实时更新。此功能特别适用于快速迭代 UI 设计并确保更改立即反映在预览窗口中。
要启用XAML 实时预览,在Visual Studio 工具栏中寻找视频摄像头图标。此图标是XAML 实时预览按钮。点击它将启用实时预览功能。

图 5.7 – XAML 实时预览按钮
注意,我们可以在调试模式下直接通过 Visual Studio 顶栏菜单打开XAML 实时预览;导航到调试 | 窗口 | XAML 实时预览。
这个操作允许我们将 XAML 预览窗口停靠在 Visual Studio 旁边,紧邻我们的代码库。当我们修改 XAML 代码时,更改几乎会立即反映在 XAML 实时预览窗口中。这允许我们立即看到更改的影响,无需保存或重新构建项目。
当鼠标悬停在元素上时,我们可以检索各种样式信息并识别定义该元素的文件。
在这个示例中,我们将鼠标悬停在MyButton元素上:

图 5.8 – 元素的样式属性
在图 5.8中,我们可以检索MyButton在MainPage.xaml中定义的TextColor和BackgroundColor值。
此外,我们可以通过滚动和缩放来平滑地与预览交互。除了使用滚动条滚动外,我们还可以利用以下交互:
-
鼠标滚轮,垂直和水平(如果鼠标支持的话)
-
触摸板两指滚动,垂直和水平
-
按下Ctrl键,配合鼠标****拖动动作
此外,对于缩放,我们可以使用以下交互:
-
底左角的放大或缩小按钮。
-
如果我们更喜欢使用键盘,可以按下Ctrl + 加号(+)或Ctrl + 减号(-)快捷键。
-
按下Ctrl键,配合鼠标滚轮动作,或者使用触摸板的捏合缩放动作。使用鼠标的一个好处是保持更精确的控制。
此外,我们可以添加标尺来帮助我们定义元素的大小和位置。标尺帮助我们将应用程序内的元素对齐。它们显示以应用单位为单位的距离。此功能有助于我们验证应用程序不同组件之间的间距。
第二组工具栏按钮控制标尺,如图 5.9 所示:

图 5.9 – 标尺工具栏
这里是工具栏提供的主要功能列表:
-
添加垂直标尺:这将添加一个单独的垂直标尺。连续多次点击此按钮会将新的标尺定位以避免与现有的标尺重叠。
-
添加水平标尺:这插入一个单独的水平标尺,其功能与垂直标尺类似。
-
删除所有标尺:这会一次性清除所有标尺。
-
选择标尺颜色:这会调整标尺的颜色。
-
切换标尺可见性:这通过单次点击切换所有标尺的可见性。
标尺设计得对键盘友好。我们可以使用Tab键在它们之间导航。利用箭头键,我们可以每次移动一个像素,或者我们可以按住Ctrl键同时使用箭头键,每次移动 10 个应用单位。按下Del键删除当前选中的标尺。此外,我们可以通过选择删除标尺按钮来使用鼠标删除标尺。
我们也可以在元素选择时添加标尺。右键单击添加垂直标尺,在右键单击的同时按住Shift键则添加水平标尺。
当在具有多个窗口的应用程序中工作时,我们可以通过使用窗口组合框来选择要显示的窗口。或者,我们可以使用应用程序工具栏中的在 XAML 实时预览中显示按钮,该按钮位于我们想要预览的窗口上,正如我们之前所看到的。
XAML 实时预览功能通过提供对 UI 变化的即时反馈,显著加快了开发过程,使得设计和调试基于 XAML 的应用程序(如 MAUI)变得更加容易。
XAML 实时预览提供了一个选择元素的功能,它反映了运行中的应用程序中的选择过程。此功能使我们能够在实时视觉树或源 XAML 中定位元素。实时视觉树是另一个帮助我们理解 MAUI 应用程序 XAML 结构的工具。
让我们探索实时视觉树提供的可能性。
实时视觉树
Visual Studio 中的 实时视觉树 功能提供了我们应用程序中 UI 元素的实时、层次视图,允许我们在 IDE 中直接检查和修改 UI 结构。此功能特别适用于调试布局问题、理解视觉树以及在开发过程中对 UI 进行动态更改。
如果您想跟随相同的代码库来展示此功能的函数,使用一个更复杂的项目,我克隆了 GitHub 仓库中的 WordPuzzle 应用程序:github.com/dotnet/maui-samples/tree/main/8.0/Apps/WordPuzzle。
使用实时视觉树功能
要利用实时视觉树功能,我们需要调试我们的应用程序。默认情况下,实时视觉树窗口位于 Windows IDE 的左侧和 Mac 的右侧。如果您找不到它,可以通过导航到顶部菜单栏 – 调试 | 窗口 | 实时 视觉树 来显示它。
当打开时,实时视觉树窗口显示了我们可以轻松探索和跟踪的 UI 元素层次结构,展示了我们的应用程序布局是如何呈现的(参见 图 5.10 ):

图 5.10 – 实时视觉树
现在我们已经介绍了实时视觉树,让我们探索顶部菜单栏。
探索实时视觉树顶部菜单栏
实时视觉树 顶部菜单栏 提供了一些方便的功能,可以帮助我们在代码库中导航并帮助我们调试布局。
图 5.11 显示了实时视觉树顶部菜单栏:

图 5.11 – 实时视觉树菜单
让我们通过全面概述我们可以如何利用它们来探索实时视觉树的这些功能:
-
在运行的应用程序中选择元素:此功能使我们能够在应用程序中选取一个 UI 元素。
然后,实时视觉树会自动更新以显示树中的相应节点及其属性。此功能对于快速识别和检查我们应用程序中的特定元素非常有价值。
-
在运行的应用程序中显示布局装饰器:此模式展示了选定对象的水平和垂直线条边界,以及指示边距的矩形。这些视觉辅助工具使对齐和间距 UI 元素变得容易,有助于识别布局问题。
-
预览选择:此模式在我们可以访问应用程序源代码的情况下,揭示了所选元素的 XAML 声明。这是一个方便的功能,可以快速导航到实时视觉树中选定元素的源代码。
-
仅我的 XAML:默认情况下,实时视觉树通过使用 仅我的 XAML 功能简化了 XAML 元素的视图。此功能隐藏了我们可能不直接感兴趣的部分,简化了通过树状结构的导航。我们可以通过在 实时视觉树 工具栏上的 显示仅我的 XAML 按钮来切换此功能的开/关。请注意,Visual Studio for Mac 目前不支持此功能。
Visual Studio 2022 提供的即时重新加载功能无缝支持实时树视图和 XAML 预览功能。即时重新加载通过监控源代码中的更改来工作。当检测到更改时,即时重新加载将更改应用到正在运行的应用程序中,而无需完全重新构建。这意味着我们可以立即看到更改的效果,而不会丢失应用程序的当前状态。
现在我们已经探索了增强 MAUI 开发体验的主要工具,在下一节中,我们将看到如何直接在设备上调试我们的应用程序。
设备调试
正如我们在本章前面所看到的,我们可以轻松地将我们的应用程序作为 通用 Windows 平台(UWP)运行,或者通过每个现有设备操作系统的模拟器。使用 Visual Studio 在设备上直接调试 .NET MAUI 应用程序涉及几个步骤。这个过程允许我们在真实设备上测试我们的应用程序,这对于测试需要特定硬件功能的特性或进行性能测试特别有用。
在本节中,我们将逐步指导如何在设备上进行调试。
在我们的设备上启用开发者模式
在设备上调试您的 MAUI 应用程序,首先激活 开发者模式 是至关重要的。然而,根据设备操作系统的不同,执行此操作的步骤也有所不同。
让我们看看在 Windows、Android 和 iOS 设备上启用开发者模式的步骤:
-
对于 Windows 设备:转到 设置 | 更新和安全 | 为开发者 并选择 开发者模式。
-
对于 Android 设备:转到 设置 | 关于手机 | 软件信息,并选择 构建号 选项,连续点击七次以解锁 开发者选项。之后,返回到 设置 | 开发者选项 并开启 USB 调试。
-
对于 iOS 设备:您需要有一台安装了 Xcode 的 Mac。将您的 iOS 设备连接到您的 Mac,打开 Xcode,转到窗口 | 设备和模拟器,选择您的设备,并启用通过网络连接。
开发者模式选项的位置可能因设备用户界面而异。如果您在查找 USB 调试时遇到困难,参考设备手册以获取指导将很有帮助。
网络设备
最后一步是将设备连接到计算机。这个过程将取决于我们的设备。让我们探索两种主要的使用案例。
安卓
当使用 Android 时,最好使用 USB,因为它是最简单、最可靠的方法。
连接后,您的设备将询问您是否信任该计算机(如果这是您第一次在其上进行调试)。您还可以选择始终允许来自此计算机以避免将来出现此提示。
或者,您还可以通过 Wi-Fi 调试 Android 设备,从而消除需要物理连接到计算机的需求。尽管这种方法需要更多设置工作,但在设备远离计算机且无法实现持续电缆连接的情况下,它可能是有益的。
带有热重启的 iOS
热重启是 Visual Studio 2022 中的一个功能,允许您快速将应用程序重新部署到 iOS 设备,而无需经过完整的构建和部署过程。这可以显著加快您的开发周期,尤其是在您频繁更改并需要在设备上测试它们时。以下是使用 Visual Studio 2022 进行 iOS 部署的热重启的使用方法。
要设置热重启,请按照以下步骤操作:
- 首先,在 Visual Studio 工具栏中,从调试目标下拉菜单中选择iOS 本地设备,然后选择本地设备。

图 5.12 – iOS 本地设备
此操作将在调试开始时启动设置热重启设置向导,引导我们设置本地 iOS 设备以进行热重启部署。然后,选择下一步以继续。
-
如果未安装 iTunes,设置向导会提示我们下载它。我们可以从 Microsoft Store 或 Apple 的网站安装 iTunes。
-
接下来,使用 USB 线将您的 iOS 设备连接到您的开发机器,并在设备上被提示时信任您的开发机器。一旦您的本地 iOS 设备被检测到,请在设置向导中点击下一步。
-
通过点击使用个人账户登录超链接并提供您的 App Store Connect API 密钥数据,配置热重启以使用您的个人 Apple 开发者计划账户。点击完成将完成设置向导,并将您的 Apple 开发者计划账户添加到 Visual Studio 中。
-
在 解决方案资源管理器 中,右键单击您的项目并选择 属性。在 iOS | 捆绑签名 下,从 方案 下拉菜单中选择 自动配置,然后点击 配置 自动配置。
-
在 配置自动配置 对话框中,选择您的 Connect API 密钥所在的团队,然后 Visual Studio 完成自动配置过程。
-
最后,点击 确定 关闭对话框。
最后一步是启动针对我们的设备的调试会话。
启动调试会话
现在,Visual Studio 将识别我们的设备,并出现直接在其上调试的选项。

图 5.13 – Android 本地设备
当我们选择 设备调试 选项时,我们的应用程序将安装在手机上。随后,我们必须启动应用程序以开始调试,这与我们在模拟器或 Windows 机器上所做的方式类似。
在了解 MAUI、探索 Visual Studio 中的工具以及在本地设备上进行调试后,您可能会发现自己有一个现有的 Xamarin 项目需要迁移到 MAUI。让我们探讨如何利用 Visual Studio 扩展轻松实现这一点。
从 Xamarin 迁移
在本节中,我们将了解如何将使用 Xamarin 编写的遗留项目迁移到前沿的 MAUI 应用程序。首先,我们将探讨 MAUI 和 Xamarin 之间的关键差异。然后,最后,我们将安装 .NET 升级助手以用于迁移我们的项目。
理解关键差异
MAUI 被认为是 Xamarin 的继任者;然而,它们之间有一些关键差异。
Xamarin 是 .NET 生态系统中的一个框架,它允许开发人员使用 C# 和 .NET 创建跨平台应用程序。它支持主要平台,如 Android、iOS 和 Windows (UWP)。Xamarin 通过将代码编译成特定平台的本地二进制文件,促进了原生应用程序的开发,确保了高性能和原生用户体验。
相反,MAUI 是 Xamarin.Forms 的下一版本,旨在进一步简化跨平台开发。它扩展了平台支持,包括 Android、iOS、macOS 和 Windows,旨在实现这些平台上的统一代码库。MAUI 优先考虑现代开发实践,专注于性能优化并提供类似原生的体验。
Xamarin.Forms 提供了一套全面的 UI 控件和布局,这些控件在每个支持的平台上都以原生方式渲染。虽然开发人员在平台之间共享代码,但 Xamarin.Forms 确保用户界面元素符合每个平台的原生外观和感觉,确保设备之间的一致性。
此外,MAUI 引入了一组全新的控件和布局,旨在提高效率和灵活性。它旨在为所有支持的平台提供现代、统一的 UI 体验,弥合原生和跨平台应用程序开发之间的差距。
为了迁移我们的遗留 Xamarin 项目,我们有两种选择——手动操作或使用升级助手。让我们探讨如何使用 .NET 升级助手。
使用 .NET 升级助手
将我们的项目迁移的一种方法是修改 Xamarin 项目的每个文件,通过创建一个新的 MAUI 项目来将其转换为 MAUI。这种方法可能耗时且需要完全理解项目。然而,对于大型和复杂的项目来说,这是一个很好的选择。
或者,我们可以使用.NET 升级助手来简化我们的过程。.NET 升级助手可以作为 Visual Studio 扩展或 .NET 命令行工具安装。在这里,我们的示例中,我们将将其用作 Visual Studio 扩展。
.NET 升级助手可以通过以下方法作为 Visual Studio 扩展或 .NET 命令行工具安装:
-
当 Visual Studio 激活时,导航到扩展|管理扩展以打开管理****扩展窗口。
-
在管理扩展窗口中,在搜索框中搜索升级。
-
选择.NET 升级助手选项,然后点击安装。

图 5.14 – 安装扩展 .NET 升级助手
-
一旦扩展下载完成,安装将在 Visual Studio 关闭时启动,然后按照说明进行安装。
-
安装后,在解决方案资源管理器中的项目节点上右键单击,并选择升级。

图 5.15 – 选择升级
-
这将打开一个窗口,让您在两个选项之间进行选择(参见 图 5.16 ):
-
就地项目升级:这将用新项目替换遗留项目。
-
并行项目升级:这将创建一个包含新 MAUI 项目的全新项目。
-

图 5.16 – 升级选项
我建议选择并行项目升级选项,以确保在升级成功完成之前,我们的工作 Xamarin 项目安全。
然后,我们只需按照向导的步骤完成升级。升级助手对于相对简单的项目是一个不错的选择。然而,在过程结束时,我们可能需要做一些手动调整。
对于复杂和大型项目,升级应手动进行,遵循 MAUI 专用书籍中找到的逐步说明。
摘要
在本章中,我们踏上了使用 Visual Studio 2022 深入多平台应用程序 UI 开发的旅程,重点关注 .NET MAUI。从揭示 .NET MAUI 的本质到掌握高效开发、跨多种设备调试以及从 Xamarin 无缝过渡的基本工具,我们已装备了构建引人入胜的多平台应用程序所需的知识和技能。
在我们的探索过程中,我们已经全面了解了.NET MAUI 的核心原则及其在现代应用开发中的重要性。我们深入研究了 Visual Studio 2022 为.NET MAUI 开发量身定制的工具库,利用它们的力量以信心和精确度创建、预览和调试应用程序。
在下一章中,我们将探索 Visual Studio 2022 的最新功能,以增强我们的 Web 开发体验。
第六章:高级网络开发工具
在本章中,我们将开始对 Visual Studio 2022 强大环境中的网络开发工具进行高级探索。我们的探索将从检查由 Web Live Preview 驱动的网络表单设计器开始,它为我们提供了一个在处理遗留 ASP.NET 网页表单应用程序时可视化和迭代设计的方法。接下来,我们将关注 Visual Studio 的 API 探索和 Dev Tunnel 功能的动态能力,增强我们的 API 开发体验。进一步丰富我们的工具集,我们将研究 Visual Studio 的 Node.js 工作负载。
在本章中,我们将涵盖以下主题:
-
由 Web Live Preview 提供的实时网页预览
-
使用 Visual Studio 的 API 探索和 Dev Tunnel
-
Visual Studio 与 Node.js 的集成
到本章结束时,凭借这些高级网络开发工具和技术,我们将能够将我们的网络项目生产力提升到新的高度。
技术要求
在编写本章时,我使用了以下版本的 Visual Studio:
-
Visual Studio Enterprise 2022 版本 17.12.0
-
预览 1.0
本章的代码文件可以在 github.com/PacktPublishing/Mastering-Visual-Studio-2022/tree/main/ch06 找到
由 Web Live Preview 提供的实时网页预览
微软宣布,当与旧框架(包括网页表单应用程序)一起使用时,ASP.NET 将继续支持旧的 .NET Framework 版本。随后,Visual Studio 2022 引入了一个由 Web Live Preview 驱动的 Web 表单项目设计器。在本节中,我们将探讨如何利用新的 Web 表单设计器以及 Web Live Preview 提供的附加功能。此功能专门针对处理遗留项目的团队。
由于此功能目前仅针对 .NET Framework 中的 Web 表单,如果您正在使用 MVC 和 .NET Core,则没有可用的表单设计器。为了保持对最新网络标准和浏览器支持的最新了解,Visual Studio 中的 Web Live Preview 使用 WebView2,它由 Microsoft Edge 驱动。
为了说明我们的示例,我们将创建一个使用 ASP.NET (.NET Framework) 的项目。
如果我们打开 default.aspx 文件或任何其他 .aspx 文件,我们会在左下角注意到两个按钮:


这些按钮允许我们以两种不同的方式显示由 Web Live Preview 驱动的设计器:全尺寸或分割在代码旁边。我们将点击 分割 按钮来观察设计器对我们代码库的影响:

图 6.2 – 分割视图
通过单击组件,我们可以编辑标签。此外,就像在 WinForm 设计器中一样,我们可以在工具箱中拖放项目,将它们放置在设计器中。
此工具箱提供了以下选项:
-
刷新:更新您的 Web 应用程序的实时预览,以反映在编辑器中做出的任何更改
-
切换设计模式:激活或停用可视化设计器界面,使我们能够在设计 UI 和直接编辑代码之间切换
-
显示空元素:在页面上显示一个空的 UI 组件,以便我们配置其属性并添加内容
-
使用实时数据:将我们的应用程序的 UI 元素动态绑定到数据源,使我们能够在开发过程中实时查看我们的应用程序如何与数据交互
-
显示源视图:打开与所选 UI 元素或控件关联的代码后置文件,使我们能够直接查看或编辑源代码:

图 6.3 – 设计器 Web 工具箱
如图 6.2所示,设计者默认显示实时数据以提供有价值的预览。在某些情况下,显示占位符可能很有价值。这就是为什么设计工具提供了使用实时数据切换选项。
在本节中,我们了解了 Visual Studio 2022 如何增强我们使用遗留 Web 框架的工作体验。现在,让我们来看看 Visual Studio 2022 为前沿 API 开发带来了什么。
使用 API 资源管理器和 Dev Tunnel 与 Visual Studio
当我们谈论 Web 开发时,API 会浮现在脑海中,用于处理每个组件的通信。在本节中,我们将探索新的 Visual Studio 功能,以增强我们在 API 开发过程中的体验。首先,我们将学习如何使用 HTTP 文件来探索我们的端点,之后我们将配置 Dev Tunnel,以便我们可以与客户、经理和同事共享我们正在开发的 API。
使用端点资源管理器生成 .http 文件
使用.http文件测试和记录 API 端点非常方便和高效。这种方法允许我们在集成开发环境(IDE)中直接简化 API 测试和开发,例如 Visual Studio、Visual Studio Code 或 IntelliJ。
使用.http文件,我们可以在我们的 IDE 中直接编写 HTTP 请求并执行它们,而无需切换到单独的工具或浏览器。这种集成使我们的开发工作流程保持在 IDE 中,从而实现快速迭代和调试,最终提高生产力。
这些 .http 文件遵循 RFC 9110 HTTP 语义标准(文档的最新版本,为理解和实现协议奠定了坚实的基础:www.rfc-editor.org/rfc/rfc9110.html),确保我们的请求格式正确且被集成到我们 IDE 中的 HTTP 客户端正确理解。这种标准化也使得文件易于携带和共享,并且可以无缝集成到我们的 CI/CD 管道中,以实现高效开发。
此外,将 .http 文件集成到我们现有的开发流程中,包括版本控制和代码审查,简化了 API 测试代码的管理,使其更易于维护和阅读。对各种 HTTP 方法、头和身份验证机制的支持为我们提供了在 API 测试方面的灵活性和强大功能。
关于 Visual Studio,对 .http 文件的支持显著简化了 API 测试过程。我们可以在 Visual Studio 中直接创建和执行 HTTP 请求,从而消除了为测试目的重新创建请求的需要,这使得整个过程更加高效和用户友好。
首先,我们可以使用 Endpoint Explorer 视图列出我们应用程序的所有端点。要打开它,我们可以使用顶部菜单栏,转到 视图 | 其他 窗口 | 端点探索器:

图 6.4 – 端点探索器
此视图显示我们在应用程序中构建的所有端点的列表。在这里,我们可以右键单击一个端点,它将显示以下两个选项:
-
在编辑器中打开:跳转到定义端点的代码
-
生成请求:在 . http 文件中编写必要的代码:

图 6.5 – 生成请求
在此示例( 图 6 .5 )中,我们正在生成 / api/cars 端点的请求:

图 6.6 – 生成的 .http 请求
现在,我们在 .http 文件中至少有一个请求,我们可以用它来测试和调试我们的端点。Visual Studio 提供了一个内置的界面来探索发送请求的响应:

图 6.7 – .http 文件响应
在测试 API 时,我们可能想要使用不同的环境。HTTP 文件允许我们在外部文件中定义环境变量。为此,我们可以创建一个名为 http-client.env.json 的文件。此文件必须放置在 .http 文件所在的同一文件夹或父文件夹中。我们必须在 JSON 文件中设置不同的环境,如下所示:
{
"dev": {
"HostAddress": "https://localhost:5128"
},
"remote": {
"HostAddress": "https://contoso.com"
}
}
现在,我们可以从文件的右上角选择我们想要发送请求的环境:

图 6.8 – 选择环境
现在,我们可以构建一个可以与团队或客户共享以测试和记录我们的 API 的文件。在某些场景中,我们可能希望通过另一台设备调试我们的 API。Visual Studio 2022 提供了一个名为 Dev Tunnel 的功能,允许我们这样做。
配置 Dev Tunnel
在 Visual Studio 2022 中,Dev Tunnel 允许开发者创建无法直接连接的机器之间的临时连接。这个特性非常适合调试和测试 Web API 和 ASP.NET Core 应用程序,尤其是在这些应用程序需要从各种设备(如移动模拟器或物理设备)访问时。当我们正在开发需要跨不同机器或设备测试的应用程序时,这是一个非常有价值的工具。
这里有一些 Dev Tunnel 可能有用的用例:
-
Web 应用程序与手机或平板电脑之间的通信
-
端口转发解决方案
-
与外部服务(例如,Twilio webhooks)的通信
我们可以通过点击调试模式按钮并选择 Dev Tunnels(无活动隧道) | 创建 隧道… 来创建一个 Dev Tunnel:

图 6.9 – 创建隧道…
之后,我们就可以访问 Dev Tunnel 的配置窗口:

图 6.10 – 配置我们的 Dev Tunnel
在此窗口中,我们可以设置以下参数:
-
账户:我们需要选择一个账户来创建 Dev Tunnel。这可能是 Azure、Microsoft Account(MSA)或 GitHub。
-
名称:在 Visual Studio 中用于识别 Dev Tunnel 的名称。
-
隧道类型:在这里,我们可以选择两种类型 – 临时或持久:
-
临时:每次启动 Visual Studio 时都会生成一个新的 URL
-
持久:每次启动 Visual Studio 时都会显示相同的 URL
-
-
访问:这允许我们设置访问级别。在这里,我们有三个选项:
-
私有:只有创建者可以访问
-
组织:同一组织内的所有用户均可访问
-
公共:免费且任何人都可以使用
-
现在,我们可以从本地主机获取一个 URL,并准备好在任何设备上共享。例如,我们可以在移动设备上使用 URL API 测试我们的应用程序,在此期间,我们可以使用 Visual Studio 2022 调试 API 调用。
当我们谈论现代高级 Web 开发时,现代 JavaScript 框架是前端工具列表中的首选。让我们看看我们如何利用 Visual Studio 进行 Node.js 开发。
Node.js 与 Visual Studio 的集成
为了开发现代 JavaScript 前端和后端,我们必须探索 Visual Studio 提供的一些功能。在本节中,我们将深入了解如何使用 Visual Studio 工作负载创建 JavaScript 项目。然后,我们将学习如何管理 npm 包,以便我们可以直接通过 Visual Studio 调试我们的 JavaScript 应用程序。
探索 JavaScript 项目模板
在 Visual Studio 2022 中,引入了一种新的项目类型,称为 JavaScript 项目系统(JSPS),它使用 .esproj 文件格式。这个系统允许我们在 Visual Studio 中直接创建独立的 Angular、React 和 Vue 项目。这些前端项目利用了我们机器上安装的相应框架的 CLI 工具,使我们能够选择我们偏好的模板版本。
首先,我们需要验证 Node.js workload 是否已正确安装在我们的 Visual Studio 实例中。为此,打开 Visual Studio 安装程序,通过单击所需 Visual Studio 实例的 更新 按钮来检查已安装的工作负载(见 图 6 .11 ):

图 6.11 – Node.js 开发 workload
确保我们安装了必要的 workload 后,我们可以探索 Visual Studio 2022 为 JavaScript 开发提供的模板。为此,我们将创建一个新的项目,并在 语言组合框 中选择 JavaScript。一旦你这样做,你将看到以下屏幕:

图 6.12 – JavaScript 模板
在这里,我们可以看到 Visual Studio 提供了几个 JavaScript 基础模板,这些模板可以分为三类:
-
ASP.NET Core 与现代 JavaScript 框架结合
-
独立 JavaScript 项目(客户端)
-
后端 Node.js 项目
对于我们的示例,我们将选择 ReactApp 模板作为独立的 JavaScript 项目。
在创建项目时,我们会看到 Visual Studio 启动一个控制台,提示输入 npm cli 命令,以便它可以创建应用程序:

图 6.13 – npm CLI
一旦我们设置了项目,我们就可以在遵循 React 或其他现代 JavaScript 框架的同时开发我们的应用程序。其中一个初始步骤是安装必要的 npm 包。虽然我们可以直接使用 npm CLI 来做这件事,但让我们看看 Visual Studio 如何帮助我们完成这个过程。
管理 npm 包
在 Visual Studio 2022 中管理 npm 包涉及使用 npm 包管理器。
从 Visual Studio 2022 开始,我们可以访问基于 CLI 的项目的 npm 包管理器。这意味着我们现在可以像下载 ASP.NET Core 项目的 NuGet 包一样下载 npm 模块。然后,我们可以利用 package.json 文件对包进行修改,并在需要时将其删除。
我们可以通过右键单击文件夹结构中的 npm 节点来访问 npm 包管理器:

图 6.14 – 调试 JavaScript 应用程序
然后,我们可以选择 安装新的 npm 包…,这将打开管理器:

图 6.15 – 安装新的 npm 包
在此窗口中,我们可以找到构建现代 JavaScript 应用程序所需的所有包。与任何应用程序开发过程一样,总有需要调试的时候。让我们来探讨 Visual Studio 如何增强我们调试现代 JavaScript 应用程序的经验。
调试 JavaScript 应用程序
使用服务器端 JavaScript 可以使我们以类似于调试 C# 应用程序的方式调试我们的应用程序。为此,我们必须遵循以下步骤:
-
设置断点:在 Visual Studio 中打开您的服务器端 JavaScript 文件(例如,server.js),然后在空白区域单击以设置断点。
-
以调试模式运行应用程序:按 F5 或转到 调试 | 开始调试 以在调试模式下运行我们的应用程序。Visual Studio 将在设置的断点处暂停执行。
-
检查应用程序的状态:在断点暂停时,我们可以通过悬停在作用域内的变量上或使用如 局部变量 和 监视 等调试窗口来检查应用程序的状态。
-
继续执行:在检查完应用程序后,再次按 F5 以继续运行我们的应用程序。
如您所见,调试服务器端 JavaScript 应用程序非常简单。现在,让我们来探讨如何调试客户端脚本。
调试客户端脚本
在 Visual Studio 中,当涉及到客户端调试时,我们为 Chrome 和 Microsoft Edge(Chromium)提供了专门的调试支持。有时,我们的调试器会自动在 JavaScript、TypeScript 以及 HTML 文件中嵌入的脚本断点处停止。
要使用 Chrome、Edge(Chromium)和 Internet Explorer 调试 ASP.NET 中的 JavaScript,我们需要通过选择 工具 | 选项 | 调试 | 常规 来导航到调试选项,然后勾选 为 ASP.NET(Chrome、Edge 和 IE)启用 JavaScript 调试 复选框:

图 6.16 – 调试选项
启用此选项确保 Visual Studio 在 ASP.NET 项目中有效地支持客户端代码的调试。
在我们之前的示例中,我们创建了一个独立的 React 应用程序,它需要我们的源代码通过 TypeScript 或 Babel 等工具进行转换。在调试期间使用源映射通过连接压缩或转换代码与其原始的、可读的格式,确保了最佳体验。这通过允许开发者在浏览器开发者工具或 Visual Studio 的调试环境中设置断点并检查其原始状态下的变量,从而简化了调试过程。
Visual Studio 自动为 TypeScript 项目生成源映射。然而,对于 JavaScript 项目,我们需要配置构建工具,如 webpack,以生成源映射。对于 TypeScript 项目,包含一个设置 sourceMap 编译器选项为 true 的 tsconfig.json 文件。对于使用 webpack 的 JavaScript 项目,配置它为 devtool: "source-map"。
接下来,确保 Visual Studio 正确配置以使用源映射。这可能涉及调整生成的源映射文件中的路径,以准确引用源文件。对于 webpack 用户,从源映射路径中移除 webpack:/// 前缀。
一旦设置了源映射,在 Visual Studio 中调试 React 项目就变得简单直接。只需将调试器附加到正在运行的应用程序上——这允许你设置断点并像代码以原始、未压缩的形式运行时一样逐步执行代码。这种简化的方法有助于快速识别和修复问题。
对于更复杂的调试场景,可能需要对项目配置进行额外调整或使用辅助工具。确保 webpack 正确配置以生成源映射。此外,在浏览器开发者工具设置中启用 JavaScript 源映射,以便在调试期间充分利用源映射。
摘要
在本章中,我们开始了对 Visual Studio 2022 强大环境中网络开发工具的高级探索。我们的旅程从对 Web Live Preview 的深入分析开始,这是一个前沿工具,能够实现实时网络预览,从而简化 Web Forms 项目的可视化设计和迭代。
然后,我们深入研究了 Visual Studio 的 API 探索和 Dev Tunnel 功能的动态能力,使开发者能够深入了解服务端点,并能够无缝集成外部 API 进行交互式开发和测试。
此外,我们探讨了 Node.js 与 Visual Studio 的集成,揭示了 JavaScript 项目模板、有效的 npm 包管理技巧以及 Visual Studio 生态系统内调试 JavaScript 应用程序的复杂性。
在下一章中,我们将深入探讨 Visual Studio 2022 与机器学习的集成,探索如何利用最新功能无缝地将机器学习模型集成到应用程序中。
第七章:机器学习集成
在本章中,我们将开始探索如何使用 Visual Studio 无缝地将 机器学习(ML)集成到软件开发工作流程中。随着我们在数字时代的不断进步,将机器学习能力集成到应用程序中变得越来越关键,这使我们能够在软件系统中实现智能决策和自动化。
我们的旅程从机器学习的简介开始,揭示其核心概念和应用。接下来,我们将通过利用 Visual Studio 中的 ML.NET 和 Model Builder 的力量来深入实际方面。通过动手示例和指导教程,我们将展示如何在熟悉的 Visual Studio 环境中直接创建和训练 ML 模型。
随着我们前进,重点转向 ML 模型的部署策略。我们将探讨如何在 ASP.NET Core web API 中部署一个训练好的模型,以实现实时推理和与基于 Web 的应用程序的集成。此外,我们还将探索在 Azure Functions 中部署模型,利用无服务器计算来实现可扩展且成本效益高的部署场景。
本章涵盖的关键主题包括以下内容:
-
机器学习简介
-
使用 ML.NET 和 Model Builder 创建机器学习模型
-
在 ASP.NET Core web API 中部署模型
-
在 Azure Functions 中部署模型
在这个旅程中,我们将解锁使用 Visual Studio 将 ML 集成到我们的软件项目中的潜力,使我们能够构建与当今技术景观相呼应的智能和自适应应用程序。
技术要求
我撰写本章时考虑的 Visual Studio 版本如下:
-
Visual Studio Enterprise 2022 版本 17.12.0
-
预览 1.0
本章的代码文件可以在github.com/PacktPublishing/Mastering-Visual-Studio-2022/tree/main/ch07找到。
机器学习简介
ML 是人工智能(AI)的一个分支,专注于开发算法和统计模型,使计算机能够在没有明确编程的情况下执行任务。这些任务可以从基本的模式识别到复杂的决策过程。在其核心,机器学习涉及机器从数据中学习以随着时间的推移提高算法的性能。
机器学习主要有三种类型:
-
监督学习:这涉及到在标记的数据上训练一个模型,根据输入数据预测输出,例如回归(预测连续值)和分类(预测离散标签)
-
无监督学习:这涉及到在未标记的数据上训练一个模型,以识别数据集中的模式或结构,例如聚类(将相似的数据点分组)和降维(减少输入变量)
-
强化学习:模型通过与环境的交互并接收奖励或惩罚形式的反馈来学习做出决策,以最大化累积奖励。
ML 利用各种算法,如决策树、支持向量机(SVMs)和神经网络,这些算法基于特定问题、数据特征和期望结果进行选择。
ML.NET 是微软的一个开源、跨平台的 ML 框架,它简化了.NET 开发者的 ML,使他们能够将 ML 功能集成到应用程序中,而无需深入的专业 ML 或数据科学知识。
ML.NET 的关键特性包括以下内容:
-
跨平台兼容性:它在 Windows、Linux 和 macOS 上无缝工作。
-
与.NET 的集成:它轻松地将 ML 功能集成到.NET 项目中。
-
可定制模型:开发者可以根据自己的需求定制模型,包括在自定义数据集上进行训练。
-
透明度和可解释性:它提供了理解模型如何进行预测的工具,这对于建立对人工智能的信任至关重要。
-
开源和社区驱动:它受益于社区贡献,导致持续改进和新特性的出现。
ML.NET是一个多功能的框架,它简化了将 ML 功能集成到.NET 应用程序中的过程。如自动 ML(AutoML)和 ML.NET CLI 以及 Model Builder 等工具使过程变得简单,即使对于没有丰富数据科学经验的开发者也是如此。它支持跨平台开发,并通过 NimbusML 无缝集成到流行的 Python 库,如 TensorFlow 和 ONNX。
ML.NET 中的 Model Builder 工具通过 AutoML 简化了模型创建过程,使开发者能够通过加载数据快速部署模型。此工具自动化了整个模型构建过程,包括为使用这些模型生成代码。结合其利用现有 ML 库的灵活性,ML.NET 为寻求将 ML 集成到其应用程序中的.NET 开发者提供了一个强大的解决方案。
现在,让我们深入了解如何使用 ML.NET 和直观的 Model Builder用户****界面(UI)创建 ML 模型。
使用 ML.NET 和 Model Builder UI 创建 ML 模型
Model Builder 最初作为 Visual Studio 2019 的一个预览功能引入,截至 2022 年已转变为一个稳定的功能。在本节中,我们将探讨如何使用 Model Builder 结合 ML.NET 创建一个机器学习模型。
首先,让我们确保 Model Builder 组件已正确安装在我们的 Visual Studio 实例中。为此,我们打开 Visual Studio 安装程序,并确认在单独组件选项卡下已选中 ML.NET Model Builder:

图 7.1 – 安装程序 – ML.NET Model Builder
然后,我们可以创建一个新的空控制台项目作为支持我们的机器学习过程的基础。现在,我们已经准备就绪,可以通过右键单击项目并选择 添加 | 机器 学习模型… 来创建我们的 ML.NET:

图 7.2 – 添加一个机器学习模型
此前的操作将启动 .mbconfig 文件。此文件是一个 JSON 文件,它跟踪 UI 的状态,包括模型的配置、数据转换、算法以及学习率、层数和神经元数量等设置。
在选择 .mbconfig 文件名称后,模型构建器提示的第一步是选择我们机器学习模型的 场景 选项。

图 7.3 – 配置 .mbconfig
模型构建器的选择窗口提供了三个主要类别组织下的几个场景:
- 表格:本类别包括回归、分类和聚类等任务的场景,其中数据以表格格式组织

图 7.4 – 表格
- 计算机视觉:本类别包括与图像分类、目标检测和其他计算机视觉任务相关的场景

图 7.5 – 计算机视觉
- 自然语言处理:本类别包括自然语言处理任务的场景,例如情感分析、文本分类和语言翻译

图 7.6 – 自然语言处理
在我们的示例中,我们将在 表格 类别下选择 数据分类 场景。
第二步是选择训练环境。根据情况,我们可以选择在本地机器上或在 Azure 云中训练我们的机器学习模型。当我们本地训练时,我们在计算机资源(CPU、内存和磁盘)的限制内操作。然而,当我们云中训练时,我们可以扩展我们的资源以满足场景的需求,特别是处理大数据集的需求。请注意,环境的可用性取决于我们选择的场景。以下是目前可用组合的表格:
| 场景 | 本地 CPU | 本地 GPU | Azure |
|---|---|---|---|
| 数据分类 | ✔️ | ❌ | ❌ |
| 值预测 | ✔️ | ❌ | ❌ |
| 推荐 | ✔️ | ❌ | ❌ |
| 预测 | ✔️ | ❌ | ❌ |
| 图像分类 | ✔️ | ✔️ | ✔️ |
| 目标检测 | ❌ | ❌ | ✔️ |
| 文本分类 | ✔️ | ✔️ | ❌ |
现在我们已经选择了场景和训练环境,我们必须收集用于训练的数据。模型构建器将根据我们选择的场景引导我们完成这个过程,帮助我们上传数据。
最后,我们可以启动我们 ML 模型的训练。我们可以为训练设置一个特定的开始时间。Model Builder 会根据我们的数据集大小自动选择训练时间。

图 7.7 – 训练
在 Evaluate 步骤中,我们将发现性能最佳的算法及其最高准确率,为我们模型的表现提供有价值的见解。此步骤还使我们能够在 UI 中直接实验模型。
在 尝试您的模型 部分,我们可以输入样本数据以生成预测。文本框预先填充了数据集的第一行数据,但我们可以修改输入并点击 预测 按钮来观察不同的价格预测。

图 7.8 – 评估
Model Builder 的最后一个面板是关于消费我们刚刚创建的模型。让我们探索如何使用 Visual Studio 将我们的模型集成到 Web API 中。
在 ASP.NET Core Web API 中部署模型
在本节中,我们将学习如何将我们的 ML.NET 模型集成到现有的 Web API 中。为此,我们将跳转到 Model Builder 的 Consume 面板。

图 7.9 – 消费
Model Builder 中的 Consume 面板是集成我们训练好的 ML 模型到 .NET 应用程序的关键工具。一旦我们完成了评估阶段,Model Builder 会生成一个模型文件以及将模型集成到我们的应用程序中所需的代码。这些模型以 .zip 文件的形式保存,并将加载和使用我们的模型的代码添加到我们解决方案中的新项目中。此外,Model Builder 还提供了一个我们可以运行的示例控制台应用程序,以查看我们的模型在实际中的应用。
Consume 面板为我们提供了创建消费我们模型的项目的选项,例如以下内容:
-
控制台应用:生成一个专门用于使用我们的模型进行预测的 .NET 控制台应用程序
-
Web API:设置 ASP.NET Core Web API,允许我们通过互联网消费我们的模型
这些项目对于将我们的模型部署到各种环境至关重要,无论是用于本地测试还是可在线访问的基于 Web 的应用程序。
让我们点击 将 Web 应用添加到解决方案 链接以创建新的 ASP.NET Core Web API,这将公开我们的模型。这将设置一个可工作的 Web API,使我们能够以最小 API 的方式公开我们刚刚训练的模型。
现在,为了了解它的表述方式,我们将查看向导为我们生成的内容。让我们探索项目结构:

图 7.10 – 生成 Web API 项目结构
模板使用以下包使 ML.NET 模型对 ML 可用:
-
Microsoft.ML
-
Microsoft.Extensions.ML
在这些库中,在 Program.cs 文件中,我们可以观察到 Visual Studio 生成了一个 POST 请求。以下是代码片段:
app.MapPost("/predict",
async (PredictionEnginePool<SampleML.ModelInput,
SampleML.ModelOutput> predictionEnginePool,
SampleML.ModelInput input) =>
await Task.FromResult(
predictionEnginePool.Predict(input)
)
);
此代码片段使用模型生成器生成的模型在 ASP.NET Core 最小 API 应用程序中设置 HTTP POST 端点 /predict。
这是因为以下代码行:
builder.Services
.AddPredictionEnginePool<SampleML.ModelInput,
SampleML.ModelOutput>()
.FromFile("SampleML.mlnet");
此代码正在配置一个 ASP.NET Core 应用程序,以使用名为 SampleML.mlnet 的文件中存储的 ML 模型进行预测。该模型期望输入为 SampleML.ModelInput 类型,并产生 SampleML.ModelOutput 类型的输出。这种设置允许应用程序在不同部分的应用程序中有效地管理和重用 ML 模型。
现在,我们可以使用端点资源管理器和 .http 文件测试端点,正如我们在 第六章 中所看到的。由于此端点使用的 HTTP 动词是 POST,我们必须在我们的请求中添加一个主体。
这是设置我们的工作请求在 . http 文件中的正确语法:
@SampleML_WebApi_HostAddress = https://localhost:63555
POST {{SampleML_WebApi_HostAddress}}/predict
Content-Type: application/json
{
"Month": "2-Jan"
}
现在,我们可以验证我们拥有一个能够消费由 Model Builder 生成的模型的 Web API。这个 Web API 可以像 .NET 生态系统中的任何其他 API 一样无缝部署。
消费我们生成的 ML 模型的另一种方法是,通过 Azure Functions 消费它。
在 Azure Functions 中部署模型
在本节中,我们将学习如何将 Model Builder 生成的 ML 模型集成到 Azure Functions 中。这个过程将不会那么直接,因为没有提供模板。
Azure Functions 是由 Microsoft Azure 提供的无服务器计算服务。无服务器计算是一种云计算执行模型,其中云服务提供商运行服务器,并动态管理机器资源的分配。计费基于应用程序实际消耗的资源数量,而不是预先购买的容量单位。
首先,我们需要确保 Azure 开发工作负载在我们的 Visual Studio 实例中安装良好,方法是导航到 Visual Studio 安装程序。

图 7.11 – Azure 开发工作负载
一旦工作负载安装完成,我们可以开始创建一个新的 Azure Functions 项目,例如,我们将将其命名为 SampleML_AzureFunction,并将所有参数保持默认设置。

图 7.12 – Azure Functions 项目
这次,我们需要自己添加这两个库,如前文所述,使用 NuGet 管理器。我们将通过右键单击项目名称,选择 管理 NuGet 包…,然后浏览所需库,最后安装它们:
-
Microsoft.ML
-
Microsoft.Extension.ML
现在,为了能够使用我们的预训练模型,我们只需要将 .mbconfig 文件复制到 Azure Functions。之后,为了确保在编译后可以访问 .mlnet 包,我们需要将 复制到输出目录属性设置为 复制 如果较新。

图 7.13 – SampleML.Net 属性
一切准备就绪后,我们可以按照以下简单步骤开发我们的函数:
-
将 startup.cs 添加到配置我们的 Azure Functions 项目以使用 SampleML.mlnet:
[assembly: FunctionsStartup(typeof(Startup))] namespace SampleML_AzureFunction; public class Startup : FunctionsStartup { public override void Configure( IFunctionsHostBuilder builder) { builder.Services .AddPredictionEnginePool< SampleML.ModelInput, SampleML.ModelOutput>() .FromFile("SampleML.mlnet"); } } -
在 Azure 的 run 方法中调用 ML.NET 包的 predict 方法:
public class FunctionML { private PredictionEnginePool< SampleML.ModelInput, SampleML.ModelOutput> _predictionEnginePool; public FunctionML( PredictionEnginePool<SampleML.ModelInput, SampleML.ModelOutput> predictionEnginePool) { _predictionEnginePool = predictionEnginePool; } [FunctionName("FunctionML")] public async Task<IActionResult> Run( [HttpTrigger( AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequest req) { string requestBody = await new StreamReader(req.Body) .ReadToEndAsync(); SampleML.ModelInput input = JsonConvert .DeserializeObject< SampleML.ModelInput>( requestBody); SampleML.ModelOutput responseMessage = await Task.FromResult( _predictionEnginePool .Predict(input)); return new OkObjectResult( responseMessage); } }
最后,我们可以使用 Endpoints Explorer 和 .http 测试 Azure 函数,就像在上一节中测试 Web API 一样。
摘要
在本章中,我们探讨了使用 Visual Studio 将 ML 功能集成到软件开发工作流程中,为开发者提供了利用应用程序中智能决策的必备技能。
我们首先介绍了机器学习(ML)的基本概念,提供了概述以理解其在现代软件开发中的应用和重要性。接下来,我们通过演示如何在 Visual Studio 中使用 ML.NET 和 Model Builder 创建和训练 ML 模型,深入到实际实施中。然后,我们探讨了训练模型的部署策略,展示了如何在 ASP.NET Core Web API 中部署 ML 模型以进行实时推理和与 Web 应用程序的集成。此外,我们还讨论了在 Azure Functions 中部署模型以利用无服务器计算进行可扩展和高效的部署场景。
在本章中,您通过使用 Visual Studio 构建、训练和部署 ML 模型获得了实践经验,使您能够将智能功能融入您的应用程序。
在下一章中,我们将继续通过 Visual Studio 2022 向高级云集成和服务迈进。
第八章:高级云集成和服务
在本章中,我们将深入探讨云集成和服务的先进领域,强调 Visual Studio 2022 如何作为一个强大的工具来开发和管理工作负载应用。在今天的数字生态系统中,云计算已成为基石,它使可扩展、弹性高和高度可用的应用成为可能。为了保持领先,开发者不仅要构建健壮的应用程序,还要将它们无缝集成到各种云平台中。
在本章中,我们将学习如何利用各种云服务的力量,简化我们的开发工作流程,并确保我们的应用程序针对云环境进行了优化。无论是将无服务器函数部署到 Azure,还是集成 Google Cloud 服务,或者利用 AWS 提供的丰富工具,本章都将为您提供在高级云开发中取得卓越成就所需的知识和技能。
本章涵盖的关键主题包括以下内容:
-
探索 .NET Aspire
-
探索 Visual Studio 2022 中的 Azure Functions 开发
-
探索 Google Cloud Tools for Visual Studio
-
探索 AWS 工具包
让我们开始我们的旅程,共同掌握云集成和构建前沿的云应用。
技术要求
在编写本章时,我使用了以下版本的 Visual Studio:
-
Visual Studio Enterprise 2022 版本 17.12.0
-
预览 1.0
为了获得最佳体验,请考虑以下内容:
-
Azure 订阅
-
Google Cloud Platform 订阅
-
AWS 订阅
本章的代码文件可以在github.com/PacktPublishing/Mastering-Visual-Studio-2022/tree/main/ch08找到
探索 .NET Aspire
2023 年 11 月,作为 .NET 8 的一部分,微软推出了 .NET Aspire。微软的动机是将 .NET 打造成为构建云原生应用最富有生产力的平台之一。这项技术可以无缝集成到流行的容器化平台,如 Docker 和 Kubernetes,从而简化应用程序及其在云原生环境中的管理和部署。在本节中,我们将探讨 .NET Aspire 是什么,以及 Visual Studio 如何引导我们完成其开发过程。
.NET Aspire 代表一套复杂的工具集,旨在简化在云环境中构建可观察、健壮和可扩展的应用程序。该框架在设计上侧重于云特定需求,旨在通过提供一系列连贯的实用工具和方法,简化开发云原生解决方案的过程。.NET Aspire 的核心方面包括以下内容:
-
针对云的框架:专门针对在云应用程序开发过程中遇到的独特挑战,.NET Aspire 强调易于观察、易于部署以及能够在分布式系统中运行的重要性。
-
基于组件的设计:作为一系列 NuGet 包呈现,这些组件满足云计算中的不同需求,允许开发者仅包含他们项目所必需的元素。这种模块化结构不仅提高了适应性,还提高了生产力。
-
简化的开发工作流程:通过引入一套统一的工具和实践,.NET Aspire 简化了适用于云的 .NET 应用程序的组装。它为数据库如 Redis 和 PostgreSQL 等提供了预配置的模块,从而简化了它们与项目的集成。
-
增强的开发工具:通过项目模板和与 Visual Studio 以及 .NET CLI 的集成,工具包丰富了开发周期,使得应用程序的启动和管理更加直接。
.NET Aspire 允许我们管理应用程序不同部分的组织和链接,使得组装相互连接的服务和识别可用资源变得更加简便。它通过提供解决与云部署相关常见问题的 NuGet 包,提供标准化的组件,为诸如监控、诊断和数据传输等任务提供预定义的设置。
通过引入结构良好的项目模板以增强应用程序的组织并加快设置阶段,以及提供关键项目如应用程序主机和默认服务,.NET Aspire 满足那些希望在云基础设施中构建可扩展、容错和可维护的应用程序的专业人士。
它对以云为中心的开发的关注使其成为 .NET 社区中的一个重要资产,使开发者能够充分利用云技术为他们的软件解决方案。
让我们探索 Visual Studio 为我们准备的 .NET Aspire 相关内容。为此,我们将使用 .NET Aspire 启动应用程序 模板创建一个新的项目。在这个例子中,我们将将其命名为 SampleAspireProject。

图 8.1 – .NET Aspire 启动应用程序模板
当你创建一个新的项目时,Visual Studio 将打开一个 概览 页面,提供有关构建和部署我们的应用程序以及服务发现的 Microsoft 文档链接:

图 8.2 – Aspire 概览页面
在同一页面上,我们可以找到更多标签页;第二个是 连接服务。通过点击此选项,我们可以访问两个选项,允许我们添加服务依赖项和服务引用。

图 8.3 – 连接的服务
点击添加服务依赖链接后,会弹出一个窗口,允许我们选择要添加到解决方案中的 Azure 服务。

图 8.4 – 添加依赖
注意,为了能够完成添加依赖的过程,我们需要一个有效的 Azure 订阅。
返回到连接的服务,然后点击添加服务引用链接。这将为我们提供一个窗口,使我们能够选择三种 API 规范之间的选择 – OpenAPI、gRPC和WCF Web Service。

图 8.5 – 添加服务引用
我们使用的模板为我们的解决方案设置了四个项目:
-
ApiService:ASP.NET Core 最小 API,作为后端逻辑层
-
AppHost:这是我们托管解决方案配置的项目
-
ServiceDefaults:表示包含默认配置和跨多个服务在解决方案中使用的潜在对象的共享项目
-
Web:这是一个 Blazor 项目,专注于前端开发。

图 8.6 – 启动应用程序组件
默认情况下,AppHost项目被设置为启动项目。因此,当我们启动解决方案时,.NET Aspire 模板会打开SampleAspireApp 仪表板窗口。

图 8.7 – .NET Aspire 仪表板
仪表板通过不同的指标,如日志、跟踪和环境配置,提供了关于我们解决方案的关键信息。在资源面板中,我们可以访问我们解决方案的每个端点。在这个模板项目中,我们在仪表板中检索了apiservice和webfrontend。
在我们云原生解决方案的本地开发完成后,我们可以直接将其发布到我们的 Azure 平台。请注意,我们需要安装 Azure Developer CLI。要创建发布配置文件,我们可以从顶部菜单重新打开概览窗口(项目 | 概览)。

图 8.8 – 发布配置文件
通过使用.NET Aspire 中的 Visual Studio,我们已经设置了一个准备部署的云原生应用程序。在下一节中,我们将探讨在 Visual Studio 中开发 Azure Functions。
探索在 Visual Studio 中开发 Azure Functions
Visual Studio 为 Azure 平台提供了几个内置模板。由于 Azure Functions 是微软最受欢迎的云原生功能,我们将在本节中重点介绍它。
简而言之,Azure Functions 是微软 Azure 提供的一种无服务器计算服务,允许开发者运行小块代码,无需担心底层基础设施。
Azure Functions 设计用于响应来自各种来源的事件,包括 HTTP 请求、计时器、数据库更改以及许多其他 Azure 服务。这种事件驱动模型使我们能够构建能够对实时数据更改做出反应、自动化任务以及与其他系统无缝集成的应用程序。
首先,我们需要确保 Azure 开发工作负载已安装在我们的 Visual Studio 实例中,方法是导航到 Visual Studio 安装程序。

图 8.9 – Azure 开发工作负载
工作负载安装完成后,我们可以开始创建一个新的 Azure Functions 项目,在这个例子中,我们将将其命名为 SampleAzureFunction。

图 8.10 – Azure Function 项目
在下一步中,Visual Studio 将引导我们到一个 附加信息 窗口,在那里我们被要求配置工作进程、触发器和授权使用。

图 8.11 – 选择 Azure Functions 触发器
让我们探索和理解 Azure Functions 提供的不同触发器选项:
-
HTTP 触发器:允许您创建一个可以调用来执行函数的 HTTP 端点。这对于创建 RESTful API 很有用。
-
带有 OpenAPI 的 HTTP 触发器:类似于 HTTP 触发器,但包括对 OpenAPI(以前称为 Swagger)的内置支持,这使得设计和记录 API 更容易。
-
IoT Hub 触发器:使函数能够响应发送到 IoT Hub 事件流的的事件。适用于处理来自 IoT 设备的遥测数据。
-
Kafka 输出:将消息写入 Kafka 主题。当您想从 Azure Function 发布消息到 Kafka 主题时使用。
-
Kafka 触发器:从 Kafka 主题消费消息。这对于在 Azure Function 内部处理来自 Kafka 主题的传入消息很有用。
-
队列触发器:每当有新消息添加到 Azure Queue Storage 队列时,执行函数。适用于处理队列任务。
-
RabbitMQ 触发器:从 RabbitMQ 队列消费消息。这对于与基于 RabbitMQ 的应用程序集成很有用。
-
SendGrid:允许您使用 SendGrid 的电子邮件服务直接从 Azure Function 发送电子邮件。这对于通过电子邮件发送通知或警报特别有用。
-
Service Bus 队列触发器:响应来自 Service Bus 队列的消息。这对于异步处理消息来说非常理想。
-
Service Bus 主题触发器:响应发布到 Service Bus 主题的消息。这对于实现发布/订阅模式很有用。
-
SignalR:使您能够在无服务器环境中运行实时消息传递 Web 应用程序。对于需要向客户端实时更新数据的场景来说非常好。
-
SQL 输入绑定:从 SQL 数据库检索数据并将其传递给函数的输入参数。这对于查询数据库和处理结果很有用。
-
SQL 输出绑定:将数据写入 SQL 数据库。这对于根据函数的执行逻辑更新数据库很有用。
-
定时器触发器:按照计划运行函数,例如每分钟、每小时或每天。这对于定期任务,如备份或报告,非常合适。
一旦我们选择了函数类型,我们必须选择授权级别以控制我们的 Azure 函数。这三种类型如下:
-
函数:此级别限制访问权限仅限于那些已被授予调用函数的特定权限的用户。通常在我们想要比其他两个级别更细致地控制对函数的访问时使用。
-
匿名:此级别允许任何客户端(认证或不认证)调用函数,而无需提供凭证。这对于公共 API 或不需要认证的函数很有用。
-
管理员:此级别授予函数完全管理权限,允许它代表调用者执行操作,就像它们以管理员身份登录一样。由于其广泛的权限,应谨慎使用。
一旦我们设置完毕,我们就可以开发函数的逻辑,并且为了回应我们的利益相关者,下一步是将它发布到我们的 Azure 订阅中:
-
在 解决方案资源管理器 中右键单击项目并选择 发布。
-
然后,选择 Azure 作为目标并点击 下一步。最后,选择 Azure 函数应用(Windows) 作为特定目标。

图 8.12 – 发布特定目标
-
然后,我们需要为我们的函数应用选择一个独特的名称,以确保它不会在全球范围内重复任何现有名称。
-
接下来,我们将从可用选项中选择我们的 Azure 订阅。我们可以选择一个现有的资源组或创建一个新的资源组。对于计划类型,我们将选择 消费 计划,以确保基于实际使用的成本效益执行。
-
我们将选择一个地理位置靠近我们的用户或服务的区域,以获得更好的性能。如果需要,我们将设置一个通用存储账户。我们还将启用 应用程序洞察 以监控和诊断我们的函数应用。
-
在部署期间,我们需要确保选择 从包运行 选项。这允许我们的函数应用直接从部署包中执行,从而提高性能并简化部署过程。在审查完所有设置后,我们将点击 发布 以开始部署。一旦部署成功完成,将显示一条成功消息。
-
最后,我们将前往 Azure 门户并导航到我们的函数应用,以确保它正在正确运行。通过门户,我们可以监控日志、测试端点并管理我们的函数。
由于 Azure 是微软生态系统的一部分,我们可以在整体企业解决方案中使用其他云平台。接下来,让我们开始探索如何使用 Visual Studio 增强我们的 Google Cloud Platform 开发。
探索适用于 Visual Studio 2022 的 Google Cloud 工具
Google Cloud Platform(GCP)是 Google 开发的一种公共云计算服务,提供各种基于云的解决方案。就像其他云平台一样,这些包括计算、存储、网络、大数据、机器学习和物联网(IoT)等服务。GCP 允许我们和企业使用 Google 的强大基础设施创建和部署应用程序和服务,并从 Google 全球网络的扩展性、灵活性和安全性中受益。在本节中,我们将探讨 Visual Studio 2022 的 GCP 扩展。
首先,我们需要通过顶栏菜单中的扩展管理器(扩展 | 管理扩展…)安装扩展,并搜索Google Cloud Tools:

图 8.13 – 扩展管理器 | Google Cloud Tools
就像安装每个新的 Visual Studio 扩展一样,我们在点击安装按钮启动修改的开始后,需要关闭我们的实例。
由于我们已经安装了 Google Cloud Tools 扩展,我们可以通过连接到我们的 Google 账户来将我们的项目部署到 App Engine。我们通过在顶栏菜单中启动 Google Cloud Explorer 来实现这一点(工具 | Google Cloud Tools | 显示 Google Cloud Explorer):

图 8.14 – 显示 Google Cloud Explorer
这将打开一个新窗口,用于输入我们有效 Google 账户的信息。

图 8.15 – 添加新账户
我们现在在扩展中拥有一个集成的部署助手,可以将您的应用程序部署到以下兼容目标:
-
用于 ASP.NET 应用程序的 Compute Engine
-
适用于 ASP.NET Core 应用程序的灵活 App Engine 和 Google Kubernetes Engine
部署助手会自动检测与我们的项目兼容的兼容目标,并引导我们完成部署过程。
可以通过选择工具 | Google Cloud Tools | 将 [项目名称] 发布到 Google Cloud,或者在解决方案资源管理器中的项目节点上右键单击并点击将 [项目名称] 发布到 Google,或者通过选择工具 | Google Cloud Tools | 发布 [项目名称] 到 Google 来调用部署助手。
注意,如果解决方案的启动项目与 Google Cloud 兼容,则将 [项目名称] 发布到 Google Cloud 菜单项才会启用。
部署助手显示与所选项目兼容的 Google Cloud 部署目标。
如果我们想更改项目,可以通过点击工具 | Google Cloud Tools | 打开云资源管理器来打开云资源管理器,并选择我们想要部署的项目。

图 8.16 – 选择要发布的产品
注意,ASP.NET 4.x 应用程序仅在 Compute Engine 上的 Windows VM 上运行。要将我们的 ASP.NET 4.x 应用程序部署到 Compute Engine,请按照以下步骤操作:
-
通过点击工具 | Google Cloud Tools | 将[项目名称]发布到 Google Cloud 来打开部署助手。
-
选择计算引擎。
-
选择Windows VM实例和部署凭据。Windows VM必须运行互联网信息服务(IIS)并能运行 ASP.NET 4.x 应用程序,例如由部署管理器创建的 VM ASP.NET。
-
选择部署的凭据。要创建 Windows 凭据,请点击管理凭据。
-
点击发布以创建我们的应用程序并将其部署到所选的虚拟机。
部署进度在 Visual Studio 输出窗口中显示,并在 Visual Studio 的系统托盘状态栏中显示进度指示器。
ASP.NET Core 应用程序的部署可以在 Docker 容器中运行,这样您的应用程序就可以在灵活的 App Engine 和Google Kubernetes Engine(GKE)环境中部署。
要部署到灵活环境,请按照以下步骤操作:
-
通过点击工具 | Google Cloud Tools | 将[项目名称]发布到 Google Cloud 来打开部署助手。
-
选择App Engine Flex以将应用程序部署到 App Engine。
-
输入我们应用程序版本的名称和流量管理选择。

图 8.17 – 将 AspNetCore 发布到 App Engine
默认版本名称基于当前系统时间。我们可以指定另一个名称。请注意,如果我们指定了一个已存在的版本名称,之前的版本将被覆盖。推广版本复选框允许我们选择是否让这个应用程序版本接收 100%的流量。如果此框被勾选,新应用程序将在部署后立即接收所有流量。
- 点击发布以创建您的应用程序并将其部署到灵活的 App Engine 环境。
就这样 – 我们的应用程序已部署,进度在 Visual Studio 输出窗口中显示。
要部署到GKE,请按照以下步骤操作:
-
通过点击工具 | Google Cloud Tools | 将[项目名称]发布到 Google Cloud 来打开部署助手。
-
选择容器引擎以部署我们的应用程序。
-
选择部署的集群,并输入您应用程序的部署名称、版本和副本实例数量。

图 8.18 – 将 AspNetCore 发布到 Kubernetes 引擎
注意三个复选框,允许我们微调我们的服务:
-
暴露服务选项指的是使我们的应用可以从 Kubernetes 集群外部访问的能力。本质上,它创建了一个 Kubernetes 服务,将我们的应用暴露给外部流量。
-
使服务公开选项与暴露服务密切相关,具体指的是使公开的服务在互联网上公开可访问。当我们选择将应用作为服务公开并使其公开时,GKE 为我们的服务分配一个公共 IP 地址,允许外部客户端访问它。
-
选择发布后打开站点将自动打开一个指向我们新部署的应用程序 URL 的网页浏览器窗口。
要创建集群,请按照以下步骤操作:
-
点击创建新集群。我们将被重定向到 Google Cloud 控制台中集群创建页面。
-
要在 Visual Studio 中显示集群,请点击刷新集群。
部署名称用于创建 Kubernetes 部署,或者如果选中,将是运行在集群上应用的服务名称。我们可以修改名称使其更具描述性。
注意,如果我们使用一个已存在的名称,旧部署将被更新而不是创建一个新的。默认版本名称基于当前系统时间。我们可以指定另一个名称。
我们可以选择将 Kubernetes 服务暴露在互联网上。通过在互联网上公开一个服务,我们获得一个公共 IP 地址,我们可以使用它来访问集群外的服务。
- 点击发布。
然后,我们的应用就被容器化在 Docker 镜像中,并在我们的容器中部署。如果我们的应用是一个公开的服务,Visual Studio 将等待服务的 IP 地址变得可用。
现在我们已经看到使用 Google Cloud Tools 将我们的应用程序优雅地部署到 Google Cloud Platform 是多么容易,我们将继续下一节,通过 AWS Toolkit 探索 Amazon 的云平台。
探索 AWS Toolkit
Visual Studio 的 AWS Toolkit 是一个扩展,旨在增强在 WS 上创建、测试和部署 .NET 应用程序的开发体验。在本节中,我们将探讨该扩展如何简化在 Visual Studio 中与 AWS 服务一起工作。
首先,我们需要通过顶部菜单中的扩展管理器(扩展 | 管理扩展…)安装扩展,并搜索AWS Toolkit with Amazon Q。

图 8.19 – AWS Toolkit with Amazon Q
就像安装每个新的 Visual Studio 扩展一样,我们在点击安装按钮以启动修改后需要关闭实例。
通过工具集集成的关键 AWS 服务包括 Amazon Simple Storage Service(S3)、Amazon Elastic Compute Cloud(EC2)、AWS Elastic Beanstalk 和 Amazon DynamoDB。
一旦安装了扩展,我们就可以通过顶栏菜单开始配置它 – 扩展 | AWS Toolkit | 入门。

图 8.20 – AWS Toolkit | 入门
这将使我们能够连接到我们的 AWS 订阅,设置 AWS Toolkit 的两个主要功能:
-
AWS Explorer:一个用于导航 AWS 服务、监控存储和管理资源的中心枢纽,可以直接从 Visual Studio 进行操作。
-
Amazon Q:代表一套综合的 AI 工具集,旨在通过利用生成式 AI 的力量和与 AWS 服务的深度集成,在组织内部的各种领域内促进更好的决策、提高生产力和简化操作。

图 8.21 – AWS 入门
AWS Explorer 设计用于为我们提供一个无缝的方式,直接从我们的开发环境中与各种 AWS 服务进行交互。它充当本地开发环境和云之间的桥梁,使我们能够执行以下任务:
- 创建和管理 AWS 资源:它允许我们轻松地在 Amazon EC2 上创建新实例,在 Amazon S3 中管理存储桶,并配置设置而无需离开 Visual Studio。现在,通过向我们的解决方案添加一个新项目,我们可以检索有关 AWS 的四个项目模板。

图 8.22 – AWS 项目模板
-
部署应用程序:通过支持 AWS Lambda,我们可以将函数和应用程序部署到我们的 AWS 订阅。
-
监控和管理:通过与 AWS CloudFormation 的集成,我们可以以代码的形式管理基础设施,确保 AWS 部署的一致性、可重复性和版本控制。
让我们考虑一个场景,其中我们想使用这个工具集通过 AWS Lambda 部署一个简单的无服务器函数。以下是我们可以如何操作:
-
本地编写函数:首先,我们在本地编写一个.NET Core 函数,彻底测试以确保其按预期工作。
-
配置部署设置:使用 AWS Explorer,我们配置部署设置,包括选择适当的运行时 (.NET Core)、设置任何必要的环境变量,并指定将执行函数的 IAM 角色。
-
部署函数:只需点击几下或执行一些命令,我们就可以将函数部署到 AWS Lambda。AWS Explorer 负责打包函数代码,将其上传到 AWS,并配置必要的触发器或事件源。
-
监控和管理:部署后,我们可以使用 AWS Explorer 来监控函数的性能,查看日志,并根据需要执行更新或更改,所有这些都可以在我们的开发环境中完成。
此示例说明了 AWS Explorer 如何与 AWS 服务集成,简化在 AWS 上运行的.NET Core 应用程序的开发生命周期,提供了一个统一的界面来创建、部署和管理云资源。
摘要
在本章中,我们探讨了使用 Visual Studio 2022 进行云集成和服务的先进方面。强调云计算在现代应用程序开发中的重要性,我们提供了详细的指南,说明如何利用 Visual Studio 的强大工具和扩展直接通过 IDE 构建和管理基于云的应用程序。
随着本章的结束,我们标志着掌握核心开发技能旅程的第二部分的结束。从高级 Web 开发到多平台、机器学习,再到现在的先进云技术,我们探讨了 Visual Studio 如何增强我们的前沿开发能力。
在即将到来的章节中,我们将继续拓展我们的视野,深入 DevOps 的世界,首先直接在 Visual Studio 中处理高级 Git 工作流程。
第三部分:通过 DevOps 实践简化协作开发
在本第三部分中,我们关注 Visual Studio 如何简化现代 DevOps 工作流程。您将了解 Visual Studio 如何简化高级 Git 工作流程,通过 GitHub Actions 自动化持续集成,并通过 Azure DevOps 促进无缝协作。此外,您将利用 Visual Studio 的 Docker 容器工具,使您能够在统一的 DevOps 环境中优化开发、测试和部署。
本部分包含以下章节:
-
第九章 ,处理高级 Git 工作流程
-
第十章 ,使用 GitHub Actions 进行持续集成
-
第十一章 ,使用 Azure DevOps 进行协作开发
-
第十二章 ,Visual Studio Docker 容器工具
第九章:处理高级 Git 工作流程
在本章中,我们将深入探讨 Visual Studio 中 Git 集成的世界,重点关注将增强我们的软件开发工作流程的实用技能。我们将专注于 Visual Studio 2022 提供的高级功能。本章旨在为您提供管理仓库、有效解决冲突和利用交互式暂存能力的工具和技术。
在本章中,我们将涵盖以下主要主题:
-
通过 Visual Studio 管理仓库
-
通过 Visual Studio 解决冲突
-
探索 Visual Studio 中的交互式暂存
为了简化我们的协作开发流程,我们将探讨掌握分支管理、解决冲突和实施交互式暂存。
技术要求
在编写本章时,我使用了以下版本的 Visual Studio:
-
Visual Studio Enterprise 2022 版本 17.12.0
-
预览 1.0
通过 Visual Studio 管理仓库
如果你熟悉开发,你可能已经使用过GitKraken或Sourcetree等工具,以及其他工具。目前,我们所有的 Git 和仓库管理都可以在 Visual Studio 中完全处理。在本节中,我们将探讨如何利用 Visual Studio 来管理我们的仓库,而无需退出我们最喜欢的 IDE。
探索管理分支窗口
Visual Studio 2022 引入了一个名为管理分支的窗口。要打开它,我们有几种选择。第一种选择是使用顶部的Git | 管理分支菜单选项:

图 9.1 – 管理分支顶部菜单选项
第二种选择是进入Git 更改窗口,然后在窗口右上角的三点菜单中选择管理分支:

图 9.2 – 管理分支 Git 更改菜单
此外,在Git 更改窗口中,如果我们有挂起的出站或入站提交,我们可以直接点击分支****组合框下方的查看提交链接。
注意,我们可以通过使用带有Ctrl + Q快捷键的功能搜索框来搜索这个功能。
此操作将打开Git 仓库窗口:

图 9.3 – Git 仓库窗口
在这个窗口中,我们可以找到我们仓库的所有分支。当我们点击一个分支时,我们可以在窗口的右侧看到其状态详情,这些详情被组织成三个部分:
-
入站:此部分显示尚未合并到当前选定分支的其他分支的更改。这些更改可能来自任何与我们本地分支相比有更新的远程分支。
-
输出:此部分显示在本地已做更改但尚未推送到远程仓库的更改。这包括自我们上次与远程分支同步以来所做的提交。
-
本地历史:此部分提供了当前选中分支的提交历史的详细视图。与专注于与其他分支相对更改的输入和输出部分不同,本地历史部分专注于选中分支内提交的按时间顺序进展。
通过此窗口,我们可以使用工具箱菜单提供的功能来组织我们的视图:

图 9.4 – 管理分支工具箱
此工具箱为我们提供了以下选项:
-
刷新:更新显示的分支、标签和其他仓库对象的列表。
-
转到子分支:直接导航到当前选中分支的子分支。子分支通常是通过分支或合并等操作从一个分支(父分支)创建的。
-
转到父分支:启用导航到当前选中分支的父分支。父分支是从中创建当前分支的分支。
-
仅显示第一个父分支:过滤视图以仅显示当前选择的直接父分支。
-
显示本地分支:隐藏任何远程分支,以便您专注于仅存在于本地机器上的分支。
-
显示远程分支:过滤视图以仅显示存在于远程仓库中的分支。
-
显示标签:使 Git 标签在Git 仓库窗口中与分支一起可见。Git 标签是对我们仓库历史中特定点的引用,通常用于标记发布版本。
-
清除历史中的切换分支:通过移除历史面板中分支旁边的切换来清理分支的历史记录。这可以使查看当前选中分支的提交历史记录更加容易,而不会被表示其他分支存在于历史中的切换所分散注意力。
使用此工具箱,我们可以与不同的分支交互并执行各种 Git 操作。要访问这些选项,我们通过在所需的分支或提交上右键单击来打开上下文菜单。

图 9.5 – Git 命令菜单
从此菜单中,我们可以处理经典的 Git 命令,如创建新分支和标签、查看提交详情、撤销提交,甚至删除更改。某些选项可能根据提交的状态而禁用。
提供的一个方便的选项是检出(--detach)。
查看检出(--detach)
在 Git 命令菜单(图 9.5)中,我们可以找到检出 (--detach)选项,它允许我们恢复到仓库的早期状态,这对于测试或运行特定时刻存在的代码特别有用。
在某些情况下,我们可能想检出远程分支的最新提交,以便快速审查拉取请求并评估最新的更新。为此,我们首先需要确保我们已经获取并更新了本地分支的副本。然后,我们可以右键单击感兴趣的远程分支并选择检出提示 提交 (--detach):

图 9.6 – 检出提示提交 (--detach)
需要特别注意,在分离头状态下做出的任何提交都没有链接到特定的分支。因此,当你切换到另一个分支时,Git 可能会删除这些提交,因为它们变得容易删除。因此,为了保护我们的工作,如果我们想保留潜在的变化,建议在从分离头状态移开之前开始一个新的分支。
处理多个仓库
为了更方便,或者根据我们团队的组织结构,我们可能会遇到跨越多个仓库构建的解决方案。这可能是一个噩梦。Visual Studio 引入了多仓库分支,这简化了这种情况。
Visual Studio 中的状态栏和Git 变更工具窗口现在都包括增强的分支选择功能,支持与多个仓库一起工作。这些工具允许我们轻松地在分支之间切换,并促进我们对所有当前活动仓库的分支管理。要快速在任何活动仓库中更改分支,只需在分支选择器中展开仓库树,然后选择要切换到的分支。

图 9.7 – 选择仓库
为了提高效率,Visual Studio 提供了将多个仓库作为单个仓库一起工作的能力。确实,我们可以通过使用顶部Git | 新建分支…菜单选项在多个仓库中创建一个新的分支。

图 9.8 – 在多仓库中创建新分支
在这里,我们可以通过复选框选择在创建新分支时要包含哪些仓库。
最后,我们可以通过管理分支功能访问和管理所有仓库和分支,使我们能够无缝地与之交互。
现在我们已经学会了如何利用 Visual Studio 2022 来管理分支,使用管理分支和多个仓库功能,在下一节中,我们将探讨共享代码库的一个重要部分:解决冲突。
通过 Visual Studio 解决冲突
解决冲突涉及识别和合并多个贡献者对同一行代码所做的更改。这个过程确保了每个人的贡献都能顺利集成,保持共享代码库的完整性和一致性。通过理解和有效管理这些冲突,团队可以确保他们的软件开发过程保持高效和高效,营造一个所有团队成员的贡献都受到重视并无缝集成的协作环境。在本节中,我们将了解 Visual Studio 2022 如何让我们处理这个过程。
在正常情况下,Git 擅长无缝集成文件修改,前提是文件内容在更新之间没有发生重大更改。当我们的分支与主分支落后很多时,在发起拉取请求之前重新设置我们的分支是明智的。这个过程确保我们的分支可以顺利地合并到主分支中,而不会遇到冲突问题。
尽管 Git 在利用仓库历史记录解决更改方面非常熟练,但合并更改有时并不清晰,Git 会停止合并并通知我们文件冲突。
因此,在这种情况下,当我们从远程分支将代码拉到本地仓库时,Visual Studio 将在 Git 变更 窗口中通过消息和列出发生冲突的文件来警告我们。

图 9.9 – 合并冲突出现
在这个例子中,Car.cs 文件在远程和本地分支上都进行了修改。在这种情况下,我们必须自己完成合并过程。为此,我们将双击相关的文件,这将以解决冲突模式打开该文件。

图 9.10 – 解决冲突模式
在此模式下,我们可以看到三个部分:
-
传入:这些是我们尝试与当前分支合并的分支所做的修改。
-
当前:这些更改指的是我们在当前分支中进行的修改。
-
结果:本节总结了合并的结果。请注意,我们可以根据自己的方便手动编辑这部分内容。
我们可能对冲突窗口的显示方式有独特的偏好。为了根据个人方便调整这些设置,只需单击界面右上角的位置图标。

图 9.11 – 更改解决冲突视图
这样,我们可以在三种模式之间切换:
-
垂直视图:结果部分位于传入和传出部分之间
-
水平视图:结果部分位于传入和传出部分下方
-
混合视图:在这里,传入和传出部分并排,结果部分位于它们下方
解决冲突模式还提供了一个工具箱,使我们能够轻松解决冲突。

图 9.12 – 解决冲突工具箱
此工具箱允许我们使用Take Incoming按钮(或按F10)自动接受来自另一个分支的所有更改。或者,我们可以点击Take Current按钮(或按F11)以保留所有冲突更改的当前版本。
在左上角,箭头使我们能够浏览文件中的差异和冲突。这样,我们可以逐行解决冲突。要合并两种修改,我们可以在每个部分的左侧使用复选框。它们在图 9.10中可见。
在成功解决所有冲突后,一个指示0 Remaining的通知将出现在屏幕左上角箭头附近。这表示没有未解决的冲突。要完成合并操作,请点击Accept Merge按钮。
最后,在我们接受合并并在所有冲突文件中重复此过程后,我们使用Git Changes窗口创建合并提交并解决冲突。在我们的日常使用案例中,我们有时会编写我们不希望立即或根本提交的代码。Git 为我们提供了对要提交的更改的精细控制,这一功能被称为暂存。在下一节中,我们将探讨 Visual Studio 如何简化此过程。
探索 Visual Studio 中的交互式暂存
暂存区域是 Git 存储有关我们将要提交的信息的地方。
暂存允许我们选择我们想要包含在下一个提交中的更改。这是 Git 的一个关键功能。主要原因是我们提供了对要提交内容的粒度和控制。通过仅暂存必要的更改,我们使项目历史更加清晰易懂。
例如,假设我们正在处理一个涉及两个函数中几个更改的功能。我们可能已经完成了一个函数的更改,但仍在处理另一个。通过暂存,我们可以提交第一个函数而不包括第二个。这样,我们的提交反映了该功能在那一刻的状态,我们的队友可以集成稳定部分,而不会被不完整的任务所分散。
自 17.6 版本以来,Visual Studio 2022 已集成交互式暂存功能。在本节中,我们将探讨如何实现。
当我们对文件进行修改时,这些修改将出现在Git Changes窗口的Changes部分上方。

图 9.13 – Changes部分
在此示例中,我们对三个文件进行了更改。默认情况下,Visual Studio 显示Commit All按钮,该按钮暂存文件中的所有更改,然后使用文本框中输入的消息提交它们。就像我们直接执行了以下命令:
git add .
git commit -m "Your commit message here"
如果我们只想暂存Car.cs文件,我们可以右键单击它并选择暂存;或者,当文件被选中时,我们可以使用右侧出现的+按钮:

图 9.14 – 暂存文件
这样,暂存更改部分就会出现,我们可以在其中找到列出的Car.cs文件:

图 9.15 – 暂存更改部分
你可能会注意到,现在Git 更改窗口将显示一个暂存提交按钮而不是提交所有按钮。在底层,Visual Studio 将执行以下git命令来暂存我们指定的文件:
git add Car.cs
如果我们回到我们的初始示例,这两个功能可以位于同一个文件中。例如,我们完成了UpdateModel()函数的实现,并将DeleteCar()置于待机状态。在这里,我们将利用交互式暂存功能,通过逐行选择我们想要暂存的更改,按照以下步骤进行:
- 在Git 更改窗口中,我们双击Car.cs文件以打开差异窗口。这将显示远程仓库和我们的本地仓库之间的差异。

图 9.16 – 差异窗口
- 一旦你确定了想要暂存的行,选中它们并点击+ 暂存行弹出按钮来添加它们:

图 9.17 – 暂存行
- 现在,在Git 更改窗口中,我们可以找到我们的Car.cs文件的两个版本:一个是在暂存更改部分中选择的行,另一个是在更改部分中的完整挂起更改。

图 9.18 – 按行暂存的文件
在暂存我们的更改后,我们可以使用带有暂存提交按钮的标准提交工作流程来提交它们。这确保了我们的提交是干净的并且逻辑上组织良好,反映了我们打算分享的更改。
在本节中,我们探讨了如何通过选择性地选择特定的更改行来正确地暂存提交。
摘要
本章深入探讨了使用 Visual Studio 管理软件开发项目的关键方面,重点关注仓库管理、解决冲突以及利用交互式暂存功能。这些课程至关重要,因为它们为我们提供了维护干净、高效的代码库并确保团队成员之间协作顺畅所需的工具和技术。
我们从深入研究 Visual Studio 管理仓库的功能开始,强调了其在简化版本控制流程中的关键作用。随后,我们探讨了在 Visual Studio 中解决冲突的艺术,提供了关于如何应对团队合作中常见的合并冲突挑战的宝贵见解。我们的旅程以对交互式暂存功能的考察结束,该功能提供了一种更用户友好的方法来准备提交。
随着我们迈向下一章节,我们将基于本章所获得的基础知识进行构建。接下来的讨论将聚焦于自动化集成过程,进一步优化项目效率和可靠性。这一过渡标志着我们在通过 Visual Studio 2022 掌握现代软件开发实践旅程中的下一个逻辑步骤,其中持续集成在持续交付高质量软件中扮演着关键角色。
第十章:使用 GitHub Actions 进行持续集成
欢迎来到使用 GitHub Actions 进行持续集成(CI)的章节。随着我们深入本章,我们将全面了解 GitHub Actions 如何增强我们的开发工作流程,简化我们的流程,并确保我们的代码库保持稳健和可靠,以及 Visual Studio 如何帮助我们实现这一点。
首先,我们将探索 GitHub Actions 的基础知识,这是一个直接集成到 GitHub 中的强大 CI/CD 工具。接下来,我们将深入了解在 GitHub Actions 中配置工作流程。本节将指导您设置和管理满足项目需求的工作流程。最后,我们将关注使用 Visual Studio 生成 GitHub Actions 文件。Visual Studio 为创建和管理 GitHub Actions 以支持 Azure 部署提供了强大的支持,使我们能够更容易地将 CI/CD 集成到开发环境中。我们将涵盖以下主题:
-
理解 GitHub Actions 在 CI/CD 中的作用
-
在 GitHub Actions 中配置工作流程
-
使用 Visual Studio 生成 GitHub Actions 文件
精通 GitHub Actions 在 CI/CD 中的使用对于任何现代开发者来说至关重要。在本章结束时,您将掌握设置和管理自动化工作流程所需的知识和技能,这将显著提高您的开发效率。
技术要求
在编写本章时,我使用了以下版本的 Visual Studio:
-
Visual Studio Enterprise 2022 版本 17.12.0
-
预览 1.0
要完全理解本章内容,您还需要一个有效的 GitHub 账户,您可以在github.com/上创建。
理解 GitHub Actions 在 CI/CD 中的作用
在本节中,我们将深入探讨 GitHub Action,了解其在 GitHub 仓库内直接自动化软件工作流程以及促进持续集成(CI)和持续部署(CD)过程中的作用。CI/CD 实践旨在加速开发周期,提高代码质量,并简化应用程序部署流程。
GitHub Actions 允许在 GitHub 仓库内直接自动化软件工作流程,包括 CI/CD 过程。通过自动化这些工作流程,可以加快开发周期,确保代码质量,并简化应用程序部署流程。这种自动化的一个例子是在将更改推送到仓库时自动运行测试。
在 CI/CD 的背景下,CI 涉及每天多次将所有开发者的工作副本合并到一个共享的主线上。这有助于快速检测和解决错误。通过频繁集成代码,团队可以在开发周期的早期识别并修复问题,从而降低后期解决这些问题的成本和努力。例如,我们可以设置一个 GitHub Action,每次将拉取请求合并到主分支时都运行单元测试。
CD 在 CI 的基础上进一步自动化,在代码变更通过 CI 管道后,将它们部署到选定的基础设施环境中。CD 确保新功能和修复能够快速且可靠地发布,从而提高软件发布过程的整体效率。GitHub 允许我们在 CI 管道中成功构建后自动将 Web 应用程序部署到预发布环境中。
GitHub Actions 为实施 CI/CD 管道提供了多项好处,包括设置简便、与 GitHub 生态系统的集成以及定制工作流程以适应特定项目需求的能力。这些好处使得它适用于各种规模的团队,从个人在个人项目上工作到管理复杂软件产品的庞大组织。团队可以轻松设置 CI/CD 管道,无需广泛的 DevOps 专业知识,从而加快开发周期并提高发布质量。
GitHub Actions 简化了 CI/CD 管道的设置,消除了手动配置的需求,例如设置网关、购买硬件和管理安全补丁。它与 GitHub 的无缝集成使其能够响应任何网关,从而实现自动化或 CI/CD 管道的灵活事件触发。GitHub 社区通过 GitHub Marketplace 贡献了大量预构建的 CI/CD 工作流程,使用户能够更容易地使用现有解决方案或分享自己的解决方案。此外,GitHub Actions 支持任何平台、语言和云,为各种技术提供了无与伦比的灵活性。
为了更好地理解这个过程,我们将探讨 GitHub Actions 的不同组件:
-
工作流程:工作流程是一个可配置的自动化过程,您可以在您的存储库中设置它以构建、测试、打包、发布或部署 GitHub 上的任何项目。工作流程使用存储在您的存储库 .github/workflows 目录中的 YAML 文件定义。YAML 最初代表 Yet Another Markup Language,但后来成为递归缩写 YAML Ain’t Markup Language。
-
事件:事件是在 GitHub 存储库中发生的事情,可以触发工作流程。例如,包括代码推送(push)、打开拉取请求(pull_request)和创建新问题(issue_comment)。
-
作业:作业是一组在同一运行者上执行的步骤。每个作业都在由 runs-on 指定的虚拟环境的独立实例中运行。
-
操作:操作是执行特定任务的代码的可重用单元,例如构建 Docker 镜像、运行测试或将内容部署到服务器。它们可以用 JavaScript(使用 Node.js)或 TypeScript 编写,并可以托管在 GitHub Marketplace 或自托管。
-
运行者:运行者是作业执行期间作业所在的服务器。运行者有两种类型:GitHub 托管运行者和自托管运行者。
在对 GitHub Actions 的概述之后,我们将学习如何配置工作流程。
配置 GitHub Actions 中的工作流程
GitHub 的所有组件都可以通过 YAML 文件进行配置。在本节中,我将解释 GitHub Actions 配置文件的组织方式,以帮助您了解其功能。
YAML 文件放置在我们仓库的 .github/workflows 目录中。这些文件被称为工作流程文件,定义了我们的 CI/CD 管道的场景。
一个典型的 GitHub Actions 工作流程配置文件由几个关键部分组成:
-
name : 为工作流程提供一个人可读的名称。
-
on : 指定触发工作流程的事件(s)。
-
jobs : 定义组成工作流程的作业。每个作业都在由 runs-on 指定的运行器环境中运行。
-
steps : 在每个作业中,步骤按顺序执行。步骤可以运行命令、设置任务或在您的仓库、公共仓库或 Docker 注册表中发布的操作中执行操作。
-
env : 允许您为作业中的所有步骤设置环境变量。
-
defaults : 为工作流程中所有作业和步骤设置默认行为。
-
permissions : 控制在作业执行期间授予 GitHub Actions 运行器的权限。
让我们通过一个针对 C#应用程序的实际 CI 工作流程来分解这些关键部分。
下面是一个我们将命名为 CI.yaml 的工作流程文件的内容:
name: C# CI
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0 # Fetches all history for all tags
# and branches
- name: Setup .NET
uses: actions/setup-dotnet@v1
with:
dotnet-version: '3.1.x' # Specify the .NET version
# you need
- name: Build
run: dotnet build --configuration Release
- name: Test
run: dotnet test --no-build --verbosity normal
现在,让我们了解这个工作流程是如何工作以及如何表达的。此文件中有四个部分,它们按以下方式组织:
Part 1: the Workflow Metadata :
-
name : C# CI
这是一个描述性的工作流程名称,使其在 GitHub UI 中更容易识别。
Part 2: the Trigger Conditions :
-
on:
-
push:
-
branches: [ main ]
这意味着每当向主分支推送时,工作流程就会运行。同样,以下工作流程将在针对主分支打开、同步或重新打开拉取请求时运行:
-
pull_request:
-
branches: [ main ]
Part 3: the Jobs :
-
jobs :
-
build:
-
runs-on : windows-latest
这指定了作业应在 GitHub Actions 提供的最新 Windows 环境中运行。这很重要,因为.NET Core/.NET 5+应用程序通常需要 Windows 环境才能正确构建和运行。
Part 4: the Steps :
每个作业由一系列按顺序执行的步骤组成。以下是每个步骤的作用:
-
检出代码:
- uses : actions/checkout@v2
此操作检查我们的仓库位于 $GITHUB_WORKSPACE 下,允许作业中的后续步骤访问它。fetch-depth: 0 选项确保获取所有标签和分支的历史记录,而不仅仅是默认分支。
-
设置.NET:
-
name : Setup.NET
-
uses : actions/setup-dotnet@v1
此操作设置 .NET 环境。dotnet-version: '3.1.x' 输入指定要使用哪个版本的 .NET。我们可以调整它以匹配我们项目的需求。
-
-
构建:
-
名称:构建
-
运行:dotnet build -- 配置 Release
此步骤使用 .NET CLI 编译应用程序。--configuration Release 标志表示构建应生成 发布构建,优化输出以获得性能。
-
-
测试:
-
名称:测试
-
运行:dotnet test --no-build -- verbosity normal
此步骤在重建项目之前运行项目中的任何单元测试(--no-build)。--verbosity normal 选项控制日志输出的数量。这有助于保持日志清洁并专注于关键信息。
-
此工作流程为 C# 项目提供了一个简单的 CI 管道,确保对主分支的每次推送或拉取请求都会自动构建和测试。通过调整 .NET 版本并可能添加更多作业或步骤,我们可以调整此工作流程以适应我们项目的特定需求。
在将我们的 YAML 文件推送到 GitHub 之后,我们现在可以转到 GitHub 仓库中的 操作 选项卡以查看我们的工作流程正在运行。当我们向主分支推送更改或打开拉取请求时,工作流程将自动运行。
使用 Visual Studio 生成 GitHub Actions 文件
在本节中,我们将了解 Visual Studio 如何帮助我们生成用于 Azure 部署的 GitHub Actions 文件。请注意,您需要有效的订阅,如 技术要求 部分所述,才能完成本节。
首先,我们需要一个可以部署到 Azure 的应用程序,为此,我简单地启动了一个 Blazor 项目,使用 Visual Studio 提供的模板,我将其命名为 BlazorServerApp。之后,按照以下步骤操作:
- 右键单击项目顶部的节点以启动发布向导并选择 Azure:

图 10.1 – 发布 Azure
- 然后,选择您想要的目标类型。选择适合您预算和公司政策的目标由您决定。对于本例,我们将选择 Azure 应用服务(Linux):

图 10.2 – 特定目标
- 一旦我们选择了目标,我们就会跳转到选择新的 应用服务。在这里,我们必须选择订阅中现有的实例。

图 10.3 – 应用服务订阅
如果没有可用的实例,您可能需要通过单击 创建一个新实例 链接并按照向导中的说明创建一个新的实例。
最后,在最后一步,我们将确定 部署类型。
- 选择 使用 GitHub Actions 工作流程进行 CI/CD(生成 yml 文件),这将根据我们的配置生成相应的 YAML 文件:

图 10.4 – 部署类型
- 现在在 解决方案资源管理器 中,我们可以看到 Blazor Server 项目,以及位于 GitHub Actions 节点下的生成的 BlazorServerApp.yml 文件。

图 10.5 – GitHub Actions 节点
我们已经看到了如何生成 GitHub Actions 文件。我们能够通过使用外部工具,例如广泛使用的静态分析解决方案 SonarCloud,来自定义它以添加代码质量到我们的管道中。GitHub Actions 是一个值得探索的强大工具,我建议您阅读 Eric Chapman 的书籍 Mastering GitHub Actions (www.packtpub.com/en-us/product/mastering-github-actions-9781805128625) 以深入了解该主题。
摘要
在本章中,我们探讨了 GitHub Actions 在 CI/CD 中的强大功能,学习了如何自动化和简化我们的开发工作流程。我们首先理解了 GitHub Actions 的基本概念。接下来,我们转向配置 GitHub Actions 中的工作流程。然后我们学习了如何编写和管理定义我们的 CI/CD 管道的 YAML 文件。在最后一节中,我们专注于使用 Visual Studio 生成 GitHub Actions 文件。Visual Studio 对 GitHub Actions 的强大支持简化了将 CI/CD 集成到您的开发环境中的过程。
在使用 GitHub Actions 自动化 CI/CD 建立了坚实的基础之后,现在是时候扩展我们的协作能力了。在下一章中,我们将探讨 Azure DevOps 如何增强团队协作,简化项目管理,并进一步优化您的开发流程。
第十一章:使用 Azure DevOps 进行协作开发
在软件开发快节奏的世界中,协作和效率至关重要。Azure DevOps 提供了一套旨在简化并增强基于团队的开发努力的工具。本章将指导您了解利用 Azure DevOps 在 Visual Studio 中进行协作开发的必要方面。
第一部分将介绍 Azure DevOps,这将提供对其核心服务和功能的基础理解。接下来,我们将介绍设置团队项目的过程,以在 Visual Studio 和 Azure DevOps 之间建立连接。然后,我们将探讨敏捷开发的原则以及如何在 Azure DevOps 中集成它们。我们将利用工作项来提高协作、可追溯性和生产力。最后,在最后一部分,我们将探讨如何在 Visual Studio 中管理构建。
在本章中,我们将涵盖以下主要主题:
-
Azure DevOps 简介
-
设置团队项目
-
实施敏捷开发实践
-
集成 Azure Pipelines 进行持续集成
到本章结束时,我们将能够有效地在 Visual Studio 中的开发工作流程中利用 Azure DevOps。
技术要求
在编写本章时,我使用了以下版本的 Visual Studio:
-
Visual Studio Enterprise 2022 版本 17.12.0
-
预览 1.0
为了完全跟随本章内容,您还需要一个有效的 Azure DevOps 账户。
Azure DevOps 简介
作为在 .NET 生态系统内工作的经验丰富的开发者,我们一直在寻找提高我们的生产力、简化我们的工作流程并确保我们的软件项目质量的方法。在本章中,我们深入探讨 Azure DevOps 的世界,这是一个由开发工具、服务和功能组成的套件,赋予团队规划工作、协作进行代码开发以及高效构建和部署应用程序的能力。
Azure DevOps 作为一款综合平台,将项目管理、版本控制、报告和自动化构建集成到单一服务中,脱颖而出。它支持基于云和本地部署模型,使其能够适应各种组织需求。通过利用 Azure DevOps,我们可以提高团队效率,增强团队成员之间的协作,并加速高质量软件解决方案的交付。
以下是我们可以利用的核心组件概述,以帮助我们在 Azure DevOps 的帮助下转变我们的开发实践:
-
Azure Boards 用于编排工作、规划冲刺和管理待办事项,以无与伦比的清晰度和精确度
-
Azure Repos 用于利用 Git 仓库的力量,确保无缝的版本控制和协作编码体验
-
Azure Pipelines 用于自动化构建和部署流程,促进持续集成,并确保我们的应用程序始终准备好发布
-
Azure 测试计划 用于简化测试阶段,使我们能够高效地创建、执行和跟踪测试
-
Azure Artifacts 用于共享包和依赖项,促进一致且高效的开发生态系统
现在我们已经熟悉了 Azure DevOps 的上下文,让我们深入了解如何在 Visual Studio 内部连接我们的 Azure DevOps 项目。
设置团队项目
要在 Visual Studio 内部有效地与 Azure DevOps 项目协同工作,我们需要在这两个之间建立连接。这包括设置我们的环境、配置项目设置,并确保 Visual Studio 和 Azure DevOps 正确集成。在本节中,我们将导航此过程。
在开始之前,请确保您有以下条件:
-
一个活动的 Azure 订阅
-
访问 Azure DevOps 组织及其内部至少一个项目
Visual Studio 允许我们通过 Team Explorer 视图连接到 Azure DevOps 项目。这种方法允许我们直接在 Visual Studio 内部访问和管理我们的 Azure DevOps 项目,而无需打开单独的 Azure DevOps 窗口。要这样做,请按照以下步骤操作:
- 导航到 视图 | Team Explorer :

图 11.1 – 打开 Team Explorer
- 在 Team Explorer 打开的情况下,点击位于 Team Explorer 窗口顶部的 管理连接 按钮,其图标为一个 电源插头 :
l

图 11.2 – 管理连接按钮
这将引导我们登录到我们的 Azure DevOps 账户。如果您尚未设置,我们可以在此处检索我们的活动 AzureDevOps 连接。
- 接下来,点击 管理连接 链接,然后点击 连接到 项目… :

图 11.3 – 连接到项目…
登录后,我们将看到一个列表,其中包含我们有权访问的 Azure DevOps 组织和项目:

图 11.4 – 连接到项目
- 选择您希望连接的项目,然后点击 连接 。此操作将在 Visual Studio 和您选择的 Azure DevOps 项目之间建立连接。
连接后,让我们看看如何利用这个连接,直接从 Team Explorer 窗口管理我们的 Azure DevOps 项目。
实施敏捷开发实践
现在,我们已经将 Visual Studio 与 Azure DevOps 项目连接起来,我们可以直接从 Team Explorer 窗口开始管理我们的 Azure DevOps 项目。在本节中,我们将回顾敏捷开发是什么以及如何利用 Visual Studio 来简化我们的敏捷流程。
介绍敏捷开发
敏捷开发是一种灵活的项目管理和软件开发方法,强调协作、客户反馈和适应变化。它于 2001 年通过敏捷宣言确立,旨在快速且持续地向客户提供价值,并不断改进流程和产品。
敏捷开发的关键方面包括以下内容:
-
以人为本而非流程:敏捷重视人际互动和协作,而非僵化的流程和工具,认识到有效的沟通对于项目成功至关重要。
-
功能性软件而非详尽的文档:敏捷团队专注于频繁交付可工作的软件,相信功能性产品比全面的文档更有价值。
-
与客户协作:敏捷开发鼓励在整个项目生命周期中与客户紧密合作,以更好地理解和满足他们的需求。
-
适应性:敏捷方法接受变化,甚至在开发后期,理解适应新的需求有助于交付真正满足客户需求的产品。
敏捷实践涉及将项目分解成更小、更易于管理的单元,称为冲刺,通常持续一到四周。在这些冲刺期间,团队协作工作,以交付产品的功能性增量,从而允许进行定期的反馈和调整。
在敏捷的背景下,工作项被用来组织、跟踪和管理项目中涉及的各种工作元素。这些元素可以包括用户故事、任务、缺陷和特性等。工作项是敏捷项目中规划和跟踪工作的基石,使团队能够捕捉关于工作的细节,分配责任,设定优先级,并跟踪进度。
在敏捷方法中,工作项通常被分类为用户故事、缺陷、任务、特性和史诗等类型,每个类型都服务于特定的目的:
-
用户故事代表了从最终用户的角度需要开发的功能。它们帮助团队理解用户的需求和原因。
-
缺陷用于跟踪在测试或开发阶段发现的软件中的错误或问题。
-
任务是需要完成以实现用户故事或解决缺陷的小型工作单元。
-
特性代表更大的功能块,可能包含多个用户故事。它们有助于将相关的工作组合在一起。
-
史诗比特性更广泛,代表跨越多个冲刺或发布的庞大工作集。
工作项对于敏捷项目管理至关重要,因为它们促进了团队成员之间的沟通,有助于优先级排序工作,并能够跟踪向项目目标迈进的过程。团队可以将工作项相互链接,以显示依赖关系,将工作汇总到更大的倡议之下,并生成报告以更好地监督项目。
敏捷团队通常使用 Azure DevOps 等工具来有效地管理工作项。这些工具为不同类型的工作项提供模板,支持根据团队流程进行定制,并提供跟踪依赖关系、管理工作负载以及通过仪表板和报告可视化进度的功能。
总结来说,工作项是敏捷实践的基本方面,提供了一种结构化的方式来规划、跟踪和管理项目生命周期各个阶段的工作。
通过 Visual Studio 管理工作项
回到团队资源管理器的主页,我们可能会注意到项目部分有三个瓷砖,其中一个名为工作项。在这个部分,我们将探讨如何通过 Visual Studio 与工作项进行交互。

图 11.5 – 团队资源管理器主页
点击瓷砖,我们可以访问我们项目的工作项列表:

图 11.6 – 可视化工作项
在此窗口中,我们可以列出所有我们的工作项。两个下拉选项分配给我和查看选项,以及文本框允许我们搜索和过滤列表。此外,在浏览器中查看链接允许我们通过浏览器直接访问 Azure 仪表板。

图 11.7 – 过滤工作项
点击工作项标题下的第一个链接,我们可以访问以下四个选项:
-
分配给我:此过滤器显示专门分配给当前登录用户的工作项。它帮助我们专注于我们的责任和任务,而不会因整个项目的工作负载而感到不知所措。
-
关注:此过滤器显示我们选择关注的工作项。这可能包括分配给他人且我们对其有利益关系或希望跟踪以进行协作或监督的任务。
-
提及:此选项过滤出提及我们的工作项。提及通常出现在评论或描述中,作为吸引他人注意特定项的一种方式。
-
我的活动:此过滤器显示我们以某种方式交互过的工作项。这可能包括创建、编辑、评论或以其他方式参与工作项。
这些团队资源管理器中的过滤选项通过允许用户根据他们在项目中的角色、兴趣和责任定制他们对工作项的视图,从而提高了生产力。
此外,查看选项链接为我们提供了管理工作项显示的选项。

图 11.8 – 查看选项
在这里,我们可以选择隐藏已完成项并在列表视图显示或详细视图之间切换。
现在我们已经看到了如何管理我们的工作项列表,让我们探索我们可以如何与这些工作项交互。我们通过右键单击其中一个来打开工作项上下文菜单。

图 11.9 – 工作项上下文菜单
此菜单包含以下操作:
-
打开:此操作将在 Azure 门户中直接以详细视图打开所选工作项。
-
新分支…:这将在我们的版本控制系统中为所选工作项创建一个新的分支。这有助于隔离与工作项相关的更改,使得跟踪和稍后审查这些更改变得更加容易。

图 11.10 – 相关工作项
这样,这个分支中的每个提交将直接包含提及相关工作项 ID 的标签在提交信息中。
-
分配给我:此操作将所选工作项分配给当前登录的用户。这是一种承担任务所有权的方式,表明我们将负责完成它。
-
完成工作项:这标志着所选工作项已完成。这通常将工作项的状态更改为表示所有必需的工作都已完成,它已准备好进行审查或关闭。
-
关联到更改:这将在版本控制系统中将所选工作项链接到特定的更改集、提交或分支。这创建了工作(代码更改)和更改原因(工作项)之间的可追溯性。这样,即使分支不是为了这个工作项而创建的,我们也可以轻松地将它链接到一个提交。
如果我们需要创建一个新的工作项,我们可以通过在工作项窗口顶部使用新建工作项链接快速完成:

图 11.11 – 创建新工作项
这将提示我们选择三种类型的工作项(问题、任务或史诗),然后出现一个简单的表单来设置标题。一旦创建,工作项将出现在我的活动过滤器下。
在 Visual Studio 中直接管理工作项可以让我们提高生产力。正确使用此功能可以增强我们开发团队中的协作、可追溯性和生产力。
正如我们在上一章中通过 GitHub Actions 所看到的,持续集成是现代应用程序开发的一个关键部分。在下一节中,我们将看到如何在 Visual Studio 中与 Azure Pipelines 交互并管理我们的构建。
集成 Azure Pipelines 进行持续集成
Visual Studio 中Team Explorer窗口的构建功能旨在帮助开发者管理、监控和与团队项目中的构建过程进行交互。它提供了一个集中界面,用于查看构建定义、排队新构建、监控正在进行的构建和审查完成的构建。此功能支持手动和自动构建过程,使团队更容易确保其软件产品的质量和可靠性。
我们可以通过点击Teams Explorer主页上的构建磁贴来访问此界面:

图 11.12 – Team Explorer 中的构建磁贴
在Team Explorer的构建部分,我们可以看到四个部分,这些部分帮助我们与 Azure 构建进行交互。

图 11.13 – Team Explorer 构建视图
该功能的基石是构建定义。这些定义了应用程序应该如何构建,包括触发构建的内容(例如,持续集成)、要包含哪些源文件以及任何预构建或后构建任务。我们可以在构建定义下找到我们项目的所有构建定义。通过点击其中一个构建,我们可以访问上下文菜单。

图 11.14 – 构建定义上下文菜单
构建定义的上下文菜单提供了几个操作,例如以下操作:
-
查看构建:此操作将通过浏览器在 Azure Devops 界面中打开构建
-
编辑构建定义...:此操作将在浏览器中的 Azure Devops 界面中以编辑模式打开构建定义,以便对其进行编辑
-
排队新构建…:我们可以从Team Explorer窗口手动排队构建,指定要使用的构建定义以及是否立即运行构建或将其安排在稍后进行
-
添加到收藏夹:将构建定义添加到收藏夹简化了对常用构建的访问,通过减少在各个构建定义之间导航的时间来提高生产力
此外,构建功能允许用户查看当前构建的状态,包括进度、成功或失败消息。这种实时反馈有助于我们快速解决问题。构建完成后,我们可以审查日志、测试结果和构建过程中生成的其他工件。这有助于故障排除并确保所有组件符合质量标准。
因此,将Team Explorer中的构建功能与 Azure DevOps 集成提供了一个强大的平台,可以直接在 Visual Studio 中管理端到端的 CI/CD 管道。这种集成提高了生产力,确保了环境间的连贯性,并支持可扩展、安全的软件交付流程。
摘要
在本章中,我们探讨了使用 Azure DevOps 进行协作开发的要点,为你提供了在 Visual Studio 内部简化开发工作流程所需的知识和技能。我们首先介绍了 Azure DevOps,强调了其核心服务,并展示了它如何与 Visual Studio 集成以增强团队协作和项目管理。
接下来,我们深入探讨了实施敏捷开发实践的方法,从对敏捷方法的全面介绍开始。我们学习了如何通过 Visual Studio 直接管理工作项,确保任务、错误和用户故事的跟踪和解决的高效性。
然后,我们学习了如何集成 Azure Pipelines 进行持续集成,引导你通过 Visual Studio 内部的构建管理。
随着我们过渡到下一章节,我们将继续扩展我们的技能集。Docker 容器已经彻底改变了我们开发、测试和部署应用程序的方式,为开发的不同阶段提供了一个一致的环境。在接下来的章节中,你将学习如何利用 Visual Studio 的强大容器工具来与 Docker 一起工作。
第十二章:Visual Studio Container Tools for Docker
在本章中,我们将深入探讨 Docker 与 Visual Studio 的强大集成,这种协同作用简化了容器管理并加速了您的开发工作流程。我们将从介绍 Docker 及其如何与 Visual Studio 集成的基础知识开始。我们将了解容器化的基本概念以及为什么它已成为现代开发实践的基础。接下来,我们将逐步介绍如何配置我们的开发环境以支持 Docker。这包括安装必要的组件、在 Visual Studio 中设置 Docker 支持以及配置项目以使用 Docker。然后,我们将深入探讨将应用程序转换为 Docker 容器的实际操作。最后,我们将探讨部署阶段。我们将学习各种将容器化应用程序部署到本地 Docker 主机、远程服务器或云平台的方法。
在本章中,我们将涵盖以下主要主题:
-
Docker 与 Visual Studio 集成的简介
-
在 Visual Studio 中设置 Docker 环境
-
使用 Visual Studio 容器化应用程序
-
部署容器化应用程序
到本章结束时,您将具备在 Visual Studio 中使用 Docker 的知识和技能,使您的开发过程更加高效和可扩展,而无需离开我们最喜欢的 IDE。
技术要求
在编写本章时,我使用了以下版本的 Visual Studio:
-
Visual Studio Enterprise 2022 版本 17.12.0
-
预览版 1.0
为了完全跟随本章内容,您还需要安装 Docker Desktop。
Docker 与 Visual Studio 集成的简介
将容器化技术(如 Docker)与强大的 IDE(如 Visual Studio)集成已成为现代应用程序开发的必要条件。本节介绍了 Docker 及其在 Visual Studio 中的无缝集成,展示了这种组合如何增强开发工作流程。
Docker 是一个开源平台,它自动化了应用程序的部署、扩展和管理。自 2013 年推出以来,Docker 利用容器化技术将应用程序及其环境依赖打包成一个标准化的单元,称为容器。
容器是轻量级、独立且可执行的包,包含运行软件所需的一切,包括代码、运行时、系统工具、库和设置。容器共享主机操作系统(OS)的内核,将应用程序进程与系统其他部分隔离开来,确保在各种环境中保持一致的性能。这种抽象优化了系统资源的使用,并简化了部署和可扩展性。
Docker 基于客户端-服务器模型,有三个主要组件:Docker 客户端、Docker 主机和 Docker Registry:
-
Docker 客户端:Docker 的主要用户界面,通过命令行界面(CLI)命令访问。用户可以构建镜像、从注册表中下载镜像、运行容器以及管理容器网络和卷。Docker 客户端与 Docker 守护进程通信,负责构建、运行和管理容器。
-
Docker 主机:容器的运行环境,包括几个关键组件:
-
Docker 守护进程:在主机机器的背景中运行,管理 Docker 容器的构建、运行和分发。它监听来自 Docker 客户端的 API 请求并管理 Docker 对象,如镜像、容器、网络和卷。
-
容器:Docker 镜像的可运行实例,封装了应用程序及其环境、库和依赖项。
-
图像:用于创建容器、包含应用程序及其所有依赖项的只读模板。
-
网络:为容器通信配置的自定义网络。
-
存储:通过卷管理 Docker 容器生成和使用的数据。
-
-
Docker 注册库:在中央存储库中存储 Docker 镜像,便于在不同主机之间共享和部署镜像。注册库可以是公共的,如 Docker Hub,也可以是私有的,用于安全存储和管理组织镜像。
Docker 的另一个关键组件是Docker 镜像。Docker 镜像是容器在特定时间点的配置快照,包含应用程序代码、运行时、库、工具和依赖项。它们是不可变的,并作为创建容器的依据。对镜像的修改会创建新的镜像,从而实现应用程序环境的持续复制。
Docker 使用 Dockerfile 来自动化 Docker 镜像的创建。Dockerfile是一个包含定义应用程序运行环境的指令的脚本。常见的指令包括以下内容:
-
FROM:这指定了基本镜像(例如,FROM mcr.microsoft.com/dotnet/sdk:9.0使用标记为版本 9.0 的.NET SDK 镜像)
-
RUN:在当前镜像之上执行新层的命令,通常用于安装软件包(例如,RUN npm install)
-
CMD:为执行 Docker 容器提供默认值(例如,CMD [" npm", "start"])
Dockerfiles 简化了容器的设置和配置,确保在开发阶段高效地定义和复制应用程序环境。
Visual Studio 为 Docker 提供了强大的支持,使开发者能够轻松地将应用程序容器化并直接从 IDE 管理容器编排。这种集成简化了开发、测试和部署容器化应用程序的过程,特别是针对目标为.NET Framework、.NET Core、ASP.NET 和 ASP.NET Core 的项目。
接下来,我们将探讨如何在 Visual Studio 内部设置 Docker 环境。
在 Visual Studio 中设置 Docker 环境
在本节中,我们将探讨如何利用 Docker 支持。Visual Studio 中的 Docker 支持为开发旨在在 Docker 容器内运行的应用程序提供了无缝体验。Docker 支持可以在项目创建期间添加到 Visual Studio 项目,也可以添加到现有项目。
创建具有 Docker 支持的项目
假设您已安装并运行 Docker Desktop,首先要做的事情是创建一个新的项目。
我们将像往常一样创建一个 ASP.NET Core 应用程序,并在附加信息窗口中勾选启用容器支持复选框:

图 12.1 – 启用容器支持
一旦勾选,它将启用两个文本框,容器操作系统和容器构建类型,以配置容器类型。根据我们的需求,我们可以为容器操作系统选项选择Windows或Linux。对于容器构建类型,我们可以选择以下任何一个:
-
Dockerfile:当您在 ASP.NET Core 应用程序中选择Dockerfile时,您正在选择手动定义如何使用 Dockerfile 构建您的容器镜像。使用 Dockerfile 可以让您完全控制容器镜像的内容,包括基础镜像、依赖项、环境变量、暴露的端口以及运行应用程序的特定命令。
-
.Net SDK:选择.Net SDK通过利用 Visual Studio 内置的容器支持简化了过程。
对于本章的以下示例,我们将选择Dockerfile选项。
将 Docker 支持添加到现有项目
如果您有一个现有项目并且想要向其添加 Docker 支持,我们遵循以下步骤:
- 要添加 Docker 支持,在解决方案资源管理器中右键单击项目,然后导航到添加 | Docker 支持...:

图 12.2 – 添加 Docker 支持
Visual Studio 将为我们的项目生成必要的 Docker 文件。

图 12.3 – Dockerfile
- 将会显示以下对话框,您需要在此配置 Docker 设置:

图 12.4 – 容器搭建选项
-
容器操作系统:此设置允许我们选择将在您的 Docker 容器内部使用的操作系统。当我们创建新项目时添加 Docker 支持,我们可以在 Linux 和 Windows 之间进行选择。
-
容器构建类型:如前所述,此设置确定您的 Docker 镜像将如何构建(例如,Dockerfile / .Net SDK)。
-
容器镜像发行版:此设置指的是容器的基础镜像发行版。当选择基于 Linux 的容器操作系统时,这一点尤其相关。
-
Docker 构建上下文:Docker 构建上下文是指 Docker 在构建镜像时位于指定路径或 URL 中的文件集。本质上,它定义了 Docker 在构建过程中可以访问的文件范围。
- 添加 Docker 支持后,我们现在可以在 Docker 容器内构建和运行我们的项目。Visual Studio 在工具栏中提供了方便的按钮,用于构建和运行您的 Docker 化应用程序。

图 12.5 – 容器运行/调试按钮
现在我们已经设置了 Docker 支持,让我们了解一下它如何可能提高我们的生产力。
使用 Visual Studio Docker 化应用程序
现在我们已经为我们的项目设置了 Docker 支持,在本节中,我们将通过 Visual Studio 的容器窗口探索我们的应用程序的 Docker 化。我们可以在窗口中检索我们容器的所有信息。要打开此窗口,请转到视图 | 其他窗口 | 容器:

图 12.6 – 打开容器窗口
在这里,我们可以找到有关解决方案容器以及 Docker Desktop 中所有容器的信息:

图 12.7 – 容器窗口
注意,Docker Desktop 必须在您的计算机上运行,以确保 Docker 引擎正在运行并提供构建、管理和运行 Docker 容器的必要环境。
容器窗口允许我们直接在 Visual Studio 中快速访问容器的信息,以便监控容器状态、查看日志以及管理容器生命周期,而无需离开 Visual Studio。
工具栏允许我们管理容器:

图 12.8 – 容器工具箱
让我们详细了解这些工具栏选项:
-
启动/停止:这些选项允许您直接从 Visual Studio 管理容器的生命周期,而无需使用 Docker CLI 命令。
-
附加调试器:对于运行支持调试的应用程序(例如 .NET Core 应用程序)的容器,此选项允许将调试器附加到容器。这使您能够设置断点并检查变量,就像应用程序在本地运行一样。
-
打开终端:这将在容器内打开一个终端会话。这在执行容器环境中的命令时特别有用。
-
删除容器:这允许您删除容器。这对于清理不再需要的已停止容器非常有用。
此外,我们还可以在右侧找到面板,允许我们咨询有关容器的所有信息。
日志窗格显示容器的日志。这对于调试和监控容器的输出非常有用:

图 12.9 – 容器 | 日志
当我们在调试模式下启动容器时,此显示会自动显示。
现在我们可以直接在 Visual Studio 中运行我们的容器,让我们看看如何部署它。
部署容器化应用程序
当应用程序开发完成后,下一步就是部署它。在本节中,我们将看到 Visual Studio 提供的内置选项以实现这一点。
首先,我们通过解决方案资源管理器右键单击项目,然后选择发布…选项来访问发布向导。

图 12.10 – 发布…
我们已经在第八章和第十章中看到,它将打开一个窗口,允许我们选择发布的目的地。在本章中,我们将关注两个选项,Docker 容器注册库和Azure。
在容器注册库中部署
让我们先回顾一下容器注册库是什么。容器注册库是一个集中存储和分发命名 Docker 镜像及其相关标签的系统。它充当容器镜像的存储库,使我们能够高效地构建、共享和部署容器化应用程序。容器注册库可以是公共的或私有的,这取决于它们是否对所有人开放或仅限于授权用户。
因此,在这种情况下,在目标窗口中,我们将选择Docker 容器注册库:

图 12.11 – Docker 容器注册库
然后,点击下一步进入特定目标选项卡以选择应用程序的主机:

图 12.12 – 特定目标容器注册库
这里,我们有三个选项:
-
Azure 容器注册库:Azure 容器注册库(ACR)是 Azure 提供的一个私有、托管和安全的 Docker 注册库。它允许我们在中央注册库中存储和管理我们的 Docker 镜像和相关工件,从而实现可靠、安全且可扩展的部署。ACR 在 Azure 的网络安全性和访问控制机制后面提供 Docker 镜像的安全存储。
-
Docker Hub:Docker Hub是一个公共的、基于云的存储库,Docker 用户和合作伙伴在其中创建、测试、存储和分发容器镜像。虽然不如 ACR 在企业使用中安全或功能丰富,但 Docker Hub 广泛用于共享开源项目和基础镜像。
-
其他 Docker 容器注册库:除了ACR和 Docker Hub,还有其他几个容器注册库可供选择,每个都有自己的功能和定价模式。其中一些值得注意的包括Google 容器注册库(GCR)和 Amazon 弹性容器 注册库(ECR)。
对于 ACR,Visual Studio 将要求我们使用有效的 Azure 订阅。另一方面,如果我们选择 Docker Hub,它将提示我们提供我们的 Docker 凭据。
在 Azure 中以服务形式部署
返回到目标窗口,我们选择Azure:

图 12.13 – 目标 Azure
这将带我们到特定目标窗口,在这里我们可以找到几个选项来在我们的 Azure 订阅上部署我们的应用程序。

图 12.14 – 特定目标 Azure
在本章中,我们将关注这些容器选项:
-
Azure 容器应用(Linux):Azure 容器应用是一个完全托管的旨在直接运行容器的服务,无需 orchestrators,如 Kubernetes。它针对运行微服务和无服务器应用程序进行了优化,内置了对源代码存储库、CI/CD 管道和自动扩展的支持。
-
Azure 应用服务容器:Azure 应用服务是一个完全托管的平台,用于构建、部署和扩展 Web 应用程序。应用服务中的容器选项允许我们运行 Docker 容器,提供了一种简单的方式来部署和管理容器化应用程序或网站。
-
Azure 容器注册表:在这里,我们检索 ACR,这是 Azure 提供的私有、托管和安全的 Docker 注册表。
每个选项都满足不同的需求,从针对微服务的优化型无服务器容器到用于 Web 应用程序的完全托管环境,再到用于 Docker 镜像的安全、私有注册表。
摘要
在本章中,我们探讨了 Docker 和 Visual Studio 之间强大的集成,这种组合显著增强了您的开发工作流程。我们从介绍 Docker 和 Visual Studio 集成开始,涵盖了 Docker 的基本知识及其在现代软件开发中的重要性。下一节指导您在 Visual Studio 中配置 Docker 支持。接下来,我们关注了将您的应用程序转换为 Docker 容器的实际方面。最后,我们讨论了 Visual Studio 中可用的各种部署策略。
通过掌握这些技能,您现在已经准备好简化您的开发过程,提高部署速度,并有效地采用现代 DevOps 实践,同时保持在 Visual Studio 中。
在下一章中,我们将深入探讨如何创建我们自己的 Visual Studio 扩展,我们将学习如何自定义和扩展 Visual Studio 以满足您独特的开发需求。
第四部分:精通核心开发技能
在本节的最后部分,我们将关注自定义和增强您的开发环境。您将学习如何编写您自己的项目模板,创建 Visual Studio 扩展,并构建 NuGet 包以与开发社区和您所在的组织共享。这些技能将使您能够根据您的需求定制 Visual Studio,简化工作流程并提高生产力。
本部分包含以下章节:
-
第十三章 ,编写您自己的项目模板
-
第十四章 ,编写您自己的 Visual Studio 扩展
-
第十五章 ,为社区创建和发布强大的 NuGet 包
第十三章:编写你自己的项目模板
在本章中,我们将深入探索 Visual Studio 的世界,通过了解如何创建自定义项目模板来展开。这些模板是极其强大的工具,使我们能够简化我们的开发过程,确保我们的团队能够以一致的结构和配置开始每个项目。我们将从剖析构成项目模板的基本结构开始,为你提供一个坚实的基础来构建。随着我们的进展,我们将发现如何将参数集成到我们的模板中,允许在项目创建点进行动态定制。最后,我们将深入研究高级功能,教你如何将项目模板扩展为完整的解决方案模板,以处理复杂的多项目解决方案。
在本章中,我们将涵盖以下主要主题:
-
理解项目模板结构
-
构建基本项目模板
-
为不同的工作流程自定义项目模板
-
集成模板参数
-
使用高级功能扩展项目模板
到本章结束时,你不仅将拥有创建和自定义项目模板的知识,还将了解如何利用这些工具来提高生产力和保持项目之间的一致性。
技术要求
在编写本章时,我使用了以下版本的 Visual Studio:
-
Visual Studio Enterprise 2022 版本 17.12.0
-
预览 1.0
本章的代码文件可以在github.com/PacktPublishing/Mastering-Visual-Studio-2022/tree/main/ch13找到。
理解项目模板结构
当我们使用 Visual Studio 创建新项目或新项目项时,我们都会使用模板。在本节中,我们将介绍项目模板和项目项模板之间的区别,然后查看涉及此过程的文件。Visual Studio 中的项目模板是强大的工具,可以帮助开发者快速设置具有预定义配置和结构的新项目。另一方面,我们可以为项目的特定部分创建项目项模板。这些模板提供了一个基础,可以根据特定需求进行定制,简化开发过程并确保项目之间的一致性。
Visual Studio 中的项目模板和项目项模板都是可重用的结构,旨在通过提供基本的代码框架和配置来简化开发,这些框架和配置可以根据特定需求进行定制。尽管它们有相似之处,但在 Visual Studio 环境中的应用范围和作用上存在显著差异。
项目模板作为创建新项目的基石蓝图。它们包括整个项目结构、必要的文件、引用和针对特定项目类型(例如,ASP.NET Core Web App、类库)定制的配置设置。当在 Visual Studio 中开始新项目时,我们选择符合我们要求的模板。此模板建立了初始项目框架,包括默认命名空间、程序集引用和编译器选项,节省时间并确保项目之间的一致性。
项目模板专注于项目中的单个组件。这些模板的范围可以从简单的文件类型(例如,XML、HTML、CSS)到涉及多个文件和资源的复杂结构。它们旨在快速将预定义的项目元素添加到现有项目中。我们在通过添加新项对话框向项目中添加新元素时使用项目模板。这可能包括从类文件或接口到预配置的网页等任何内容。项目模板允许快速包含这些元素,而无需手动配置。
创建新模板涉及与以下要点中描述的不同文件一起工作:
-
要创建的文件:
-
源代码文件:这些是模板中包含的初始编码文件。例如,C#类库模板可能以默认的Class1.cs文件开始。
-
嵌入式资源:此类别包括项目可能需要的图像、配置文件或其他资源。
-
项目文件:这些包括解决方案和项目文件(例如,C#项目的.sln和.csproj文件),它们概述了项目的结构和依赖关系。
-
-
. vstemplate:
-
此 XML 文件对于定义模板至关重要。它包含有关模板的元数据,例如模板的名称、描述、图标和项目类型。
-
它概述了要包含在项目中的文件,并指定了在实例化模板时需要处理的任何附加参数或向导数据。
-
-
压缩成一个 ZIP 文件:
-
一旦准备好模板及其相关文件,它们就会被压缩成一个.zip文件。此文件放置在 Visual Studio 可以识别的特定文件夹中。
-
对于项目模板,.zip文件放置在\Documents\Visual Studio < 版本>\Templates\ProjectTemplates目录中。
-
对于项目模板,它们位于\Documents\Visual Studio < 版本>\Templates\ItemTemplates目录中。
-
Visual Studio 中的项目模板为整个项目提供了一个起点,提供了一个基于所选模板规格的结构化基础。相反,项目项模板用于加速在项目内添加单个组件或文件,通过提供可重用的代码片段或资源来简化开发工作流程。理解这两种模板之间的区别可以显著提高软件开发实践中的生产力和一致性。
现在,让我们学习如何创建基本模板。
构建基本项目模板
在本节中,我们将介绍构建项目模板的更便捷方法。该过程包括构建一个具有最小需求的骨架项目,以满足我们公司的要求,例如。之后,我们可以使用 Visual Studio 的导出模板向导,通过使用 Visual Studio 顶栏菜单:项目 | 导出模板…将现有项目导出为模板:

图 13.1 – 导出模板…
上述操作将打开导出模板 向导窗口:

图 13.2 – 导出模板向导
首先,我们选择要导出的模板类型;要么是项目模板,要么是项模板。
然后,该工具允许我们定义关键细节,例如模板的名称、描述、图标和预览图像。

图 13.3 – 选择模板选项
完成后,项目将被打包成一个.zip文件并保存到所选输出位置。此外,我们可以选择直接将模板导入 Visual Studio 以立即使用。要访问和使用我们新创建的模板,请打开创建新项目的对话框。

图 13.4 – 使用自定义模板
我们可以通过搜索其名称或浏览列表来定位模板。请注意,对于自定义模板,可能不支持按语言或项目类型进行筛选。
让我们探索如何自定义模板。
为不同工作流程自定义项目模板
更新 Visual Studio 模板有两种方式,要么使用导出模板向导,要么手动调整模板内的文件。
第一种方法是利用导出模板向导,通过在我们要修改的项目模板内启动一个新项目,然后按照以下步骤进行:
-
在项目内执行我们想要的修改。这可能包括更改输出类型、添加新文件或实施其他更改。
-
导出修改后的模板:在调整了我们的项目后,转到项目 | 导出模板以访问导出模板向导。
-
完成导出过程:遵循向导的说明,成功导出我们修改后的模板为.zip文件。
另一种选择是将手动修改应用于模板,通过以下步骤修改.vstemplate文件:
-
识别模板:找到我们打算修改的模板对应的.zip存档。通常,它位于%USERPROFILE%\Documents\Visual Studio
\Templates\ProjectTemplates 。 -
解压缩存档:提取模板存档的内容。
-
编辑文件:对模板中的文件进行必要的编辑、添加或删除。
-
修改 .vstemplate 文件:调整.vstemplate XML 文件以准确反映所做的更改。
-
存档更改:将所有修改后的文件压缩回一个.zip存档。
-
实施更新后的模板:将新压缩的.zip文件传输到原始目录,替换过时的模板文件。
定制化允许我们在现有模板中使用一些参数和变量。让我们在下一节中看看如何实现这一点。
集成模板参数和变量
现在我们已经看到了如何打开现有的.vstemplate文件以进行自定义,在本节中,我们将探讨如何利用参数在模板实例化时动态替换模板中的值。使用 Visual Studio 中的.vstemplate文件中的参数和变量,我们可以创建动态模板,这些模板可以适应不同的项目名称、命名空间和其他可定制方面。此功能增强了模板的可重用性和可定制性,使模板创建成为简化开发工作流程的有力工具。
模板参数是我们模板中的占位符,在模板实例化时用实际值替换。这些参数可以代表我们项目的各个方面,例如项目名称、命名空间,甚至自定义定义的值。
Visual Studio 提供了一组保留的模板参数,您可以直接在模板中使用这些参数。以下是这些保留参数的列表,根据微软的文档:
-
clrversion:当前版本的公共语言****运行时(CLR)。
-
ext_:添加到任何参数前缀,以引用父模板中的变量(例如,ext_safeprojectname*)。
-
guid[1-10]:用于在项目文件中替换项目 GUID 的 GUID。最多可以指定 10 个唯一的 GUID(例如,guid1)。
-
itemname:使用参数的文件的名称。
-
machinename:当前计算机名称(例如,Computer01)。
-
projectname:用户在创建项目时提供的名称。这仅适用于项目模板。
-
registeredorganization:来自HKEY_LOCAL_MACHINE\Software\Microsoft\WindowsNT\CurrentVersion\RegisteredOrganization的注册表键值。
-
rootnamespace : 当前项目的根命名空间,后跟当前项的子文件夹,斜杠被点号替换。
-
defaultnamespace : 当前项目的根命名空间。
-
safeitemname : 与 itemname 相同,但将所有不安全字符和空格替换为下划线字符。
-
safeitemrootname : 与 safeitemname 相同。
-
safeprojectname : 在创建项目时用户提供的名称,但已移除所有不安全字符和空格。这仅适用于项目模板。
-
targetframeworkversion : 目标 .NET Framework 的当前版本。
-
time : 基于 Windows 用户设置的格式(例如,DD/MM/YYYY 00:00:00)的当前时间。
-
specifiedsolutionname : 解决方案名称。行为取决于是否勾选了将解决方案和项目放在同一目录中或创建解决方案目录。
-
userdomain : 当前用户域。
-
username : 当前用户名。
-
webnamespace : 当前网站的名称,用于网页表单模板以确保类名唯一。
-
year : 当前年份,格式为 YYYY。
-
solutiondirectory : 解决方案的目录。
-
destinationdirectory : 创建 .csproj 后的目录路径。
这些保留参数可以用于在模板中动态插入项目特定的信息。例如,我们可以使用 \(safeprojectname\) 和 \(year\) 保留参数动态生成命名空间并添加版权声明。
对于这个例子,我们将手动创建一个新的模板。本例将重点创建一个使用多个保留模板参数的 C# 类库项目模板,这些参数根据用户输入和系统信息动态生成命名空间、类名和文件名。让我们从以下步骤开始:
-
首先,在 .vstemplate 文件中定义我们的项目模板结构。此文件指定在实例化模板时创建的内容:
<VSTemplate Version="3.0.0" xmlns="http://schemas.microsoft.com/developer/ vstemplate/2005" Type="Project"> <TemplateData> <Name>Masterize VS ClassTemplate</Name> <Description>TemplateParametre</Description> <ProjectType>CSharp</ProjectType> <SortOrder>1000</SortOrder> <CreateNewFolder>true</CreateNewFolder> <DefaultName>ClassTemplate</DefaultName> <ProvideDefaultName>true</ProvideDefaultName> <LocationField>Enabled</LocationField> <EnableLocationBrowseButton> true </EnableLocationBrowseButton> <CreateInPlace>true</CreateInPlace> <Icon>__TemplateIcon.ico</Icon> </TemplateData> <TemplateContent> <Project TargetFileName="ClassTemplate.csproj" File="ClassTemplate.csproj" ReplaceParameters="true"> <ProjectItem ReplaceParameters="true" TargetFileName="Class1.cs"> Class1.cs </ProjectItem> <ProjectItem ReplaceParameters="true"> Properties\AssemblyInfo.cs </ProjectItem> </Project> </TemplateContent> </VSTemplate>注意,如果需要为每个 ProjectItem 指定 TargetFileName 以确保它们在新建的项目中具有特定的名称,这是一个常见的做法。第二个
(Properties\AssemblyInfo.cs)没有 TargetFileName。如果您想确保此文件在新项目中具有相同的名称,这是可以的。如果您想替换参数,它也应该具有 ReplaceParameters="true" 属性(如当前所示)。 -
接下来,创建一个名为 Class1.cs 的 C# 类文件,该文件将成为我们模板的一部分。我们将使用 \(safeprojectname\) 和 \(year\) 保留参数动态生成命名空间并添加版权声明:
using System; namespace $safeprojectname$ { /// <summary> /// Represents a simple class in the /// $safeprojectname$ project. /// Copyright (c) $year$ by Company name /// </summary> public class Class1 { public Class1() { Console.WriteLine( "Hello from $safeprojectname$!" ); } } } -
我们还将在模板中的 Properties 文件夹下创建一个 AssemblyInfo.cs 文件。此文件将包含程序集元数据,我们将使用 \(projectname\)、\(year\) 和 \(username\) 保留参数来自定义程序集标题和版权信息:
using System.Reflection; using System.Runtime.CompilerServices; [assembly: AssemblyTitle("$projectname$")] [assembly: AssemblyDescription("A simple class library project.")] [assembly: AssemblyCompany("Your Company")] [assembly: AssemblyProduct("$projectname$")] [assembly: AssemblyCopyright("Copyright © $year$ $username$. All rights reserved.")] [assembly: AssemblyTrademark("")] [assembly: AssemblyVersion("1.0.*")] -
创建这些文件后,将它们打包成.zip文件,并将它们放置在 Visual Studio 模板目录中,或者通过 Visual Studio 的模板管理器导入它们。
当基于此模板创建新项目时,Visual Studio 将提示我们输入项目名称和位置。因此,Class1.cs文件将填充提供的值:

图 13.5 – 生成 Class1
然后,它将用实际值替换模板文件中的保留参数,例如安全的项目名称、当前年份和用户名。在这个例子中,我选择DummyTemplate作为项目名称,系统使用当前年份来设置\(** **year\)参数。
当我们从自定义模板创建项目时,你可能会注意到我们可以使用过滤器组合框来过滤它们。在我们的.vstemplate文件的
-
:这指定了模板中使用的编程语言 -
:这表示目标平台(例如,Windows,Web) -
:这描述了项目的类型(例如,类库、控制台应用程序)
每个标签元素应包含标签的名称作为其文本内容:
<TemplateData>
…
<LanguageTag>C#</LanguageTag>
<PlatformTag>Windows</PlatformTag>
<ProjectTypeTag>Class Library</ProjectTypeTag>
</TemplateData>
以这种方式更新我们的模板时,我们可以观察到模板列表中描述上出现的标签。

图 13.6 – 带有标签的模板列表
这些标签允许我们在寻找模板时利用列表上的三个过滤器。
有时候,我们需要不止一个项目,并且我们期望使用一个带有多库项目的现成解决方案来构建一个干净的架构,例如;让我们在下一节中看看我们如何实现这一点。
扩展项目模板以包含高级功能
在本节中,我们将通过结合多个项目模板来创建一个可以称为解决方案模板的内容。
在 Visual Studio 中创建一个多项目解决方案模板涉及几个步骤,包括创建单个项目模板,将它们组合成一个解决方案模板,并配置解决方案模板在创建时实例化多个项目。让我们开始吧:
-
首先,创建将包含在解决方案模板中的模板。为此,请遵循本章“构建基本项目模板”部分提供的说明。
-
接下来,为解决方案模板准备一个目录结构。这包括为解决方案模板创建一个文件夹,并将每个项目模板解压缩的内容复制到这个文件夹中。

图 13.7 – 文件夹结构
-
在这个例子中,我创建了三个项目模板来构建解决方案。
-
现在,在解决方案模板目录的根目录下创建或修改一个 .vstemplate 文件。此文件定义了我们的解决方案模板的结构,包括对各个项目模板的引用。在此文件中,我们将 Project Type 选项设置为 ProjectGroup,以表明此模板代表一组项目,如下所示:
<VSTemplate Version="3.0.0" xmlns="http://schemas.microsoft.com/developer/ vstemplate/2005" Type="ProjectGroup"> <TemplateData> <Name>CleanDummyArch</Name> <Description>Dummy solution</Description> <ProjectType>Web</ProjectType> <ProjectSubType>CSharp</ProjectSubType> <SortOrder>1000</SortOrder> <CreateNewFolder>true</CreateNewFolder> <DefaultName>DummySolution</DefaultName> <ProvideDefaultName>true</ProvideDefaultName> <LocationField>Enabled</LocationField> <EnableLocationBrowseButton> True </EnableLocationBrowseButton> <CreateInPlace>true</CreateInPlace> <Icon>__TemplateIcon.ico</Icon> <LanguageTag>C#</LanguageTag> <PlatformTag>Windows</PlatformTag> <ProjectTypeTag>Class Library</ProjectTypeTag> </TemplateData> <TemplateContent> <ProjectCollection> <ProjectTemplateLink ProjectName="$safeprojectname$"> Dummy\MyTemplate.vstemplate </ProjectTemplateLink> <ProjectTemplateLink ProjectName="$safeprojectname$.Application"> Application\MyTemplate.vstemplate </ProjectTemplateLink> <ProjectTemplateLink ProjectName="$safeprojectname$.Models"> Models\MyTemplate.vstemplate </ProjectTemplateLink> </ProjectCollection> </TemplateContent> </VSTemplate> -
在
中,我们使用 而不是 来定义一组项目。每个子项目通过一个 元素链接,该元素建立链接,指向解决方案模板目录中项目模板的相对路径。 -
一旦我们的解决方案模板配置完成,我们将执行以下操作:
-
我们将解决方案模板目录的内容进行压缩,包括修改后的 .vstemplate 文件和未压缩的项目模板
-
我们将压缩文件放置在 Visual Studio 模板目录中或通过 Visual Studio 的模板管理器导入它
-
-
最后,通过在 Visual Studio 中从它创建一个新项目来测试解决方案模板,以确保它能够正确地生成包含所有所需项目的解决方案,通过解决方案资源管理器。

图 13.8 – 解决方案架构
因此,我们启动了一个包含三个项目的解决方案,正如模板中定义的那样。这个过程允许我们创建一个可重复使用的解决方案模板,该模板包含多个项目,简化了基于预定义配置的新解决方案的设置,节省了时间并确保了项目之间的一致性。
摘要
在本章中,我们探讨了在 Visual Studio 2022 中制作自定义项目模板的艺术,这对于任何希望标准化和加速其工作流程的开发者来说是一项关键技能。我们首先理解了构成项目模板骨架的基本结构。然后我们深入到定制中,向您展示如何调整这些模板以适应不同的工作流程,确保它们满足您项目的特定需求。从那里,我们探讨了参数的集成,允许您向模板添加动态元素以获得更大的灵活性。最后,我们将重点扩展到高级功能,使您能够轻松创建可以管理复杂的多项目解决方案的解决方案模板。
随着我们继续前进,我们将通过探索 Visual Studio 的另一个强大功能:创建自己的扩展来构建这一知识。在下一章中,我们将深入到自定义工具的世界,在那里你将学习如何通过创建和部署针对你独特需求的扩展来进一步增强你的开发环境。
第十四章:编写您自己的 Visual Studio 扩展
在本章中,我们将深入 Visual Studio 扩展开发的领域,我们将学习如何创建能够增强我们的开发环境的工具。Visual Studio 扩展功能强大,能够添加自定义功能、自动化重复性任务以及创建满足特定需求的定制工作流程。
我们将首先分解 Visual Studio 扩展架构,这将为我们提供一个对其核心组件及其在 集成开发环境(IDE)中如何工作的坚实基础。有了这个基础,我们将使用提供的项目模板构建和测试我们的第一个扩展。随着我们的进步,我们将探索更复杂的功能,检查预加载模板提供的功能。最后,我们将介绍部署和共享过程,确保我们能够有效地分发我们的扩展,无论是用于个人使用、团队内部还是更广泛的开发者社区。
在本章中,我们将涵盖以下主要主题:
-
理解 Visual Studio 扩展架构
-
构建您的第一个扩展
-
高级扩展功能
-
部署和共享您的扩展
到本章结束时,您将掌握创建、优化和共享 Visual Studio 扩展所需的知识和实践技能,这将显著提高您的生产力。
技术要求
在编写这一章时,我使用了以下版本的 Visual Studio:
-
Visual Studio Enterprise 2022 版本 17.12.0
-
预览 1.0
理解 Visual Studio 扩展架构
Visual Studio 扩展 是增强 Microsoft Visual Studio 功能的强大工具,允许开发者自定义和扩展 IDE,以更好地满足他们的开发需求。本节深入探讨了 Visual Studio 扩展的底层架构,突出了关键组件、它们之间的交互以及它们所运行的更广泛生态系统。
Visual Studio 扩展建立在称为 Visual Studio Shell 的强大基础之上,该 Shell 作为与 IDE 交互的核心环境。这个 Shell 具有高度的可定制性,提供了一个框架,使我们能够无缝地创建和集成新功能。开发扩展的过程始于 扩展清单,这是一个包含基本元数据的关键文件,例如扩展的名称、版本、描述和依赖项。这个清单对于 Visual Studio 中的安装过程至关重要,一旦扩展部署,它在管理更新中也发挥着重要作用。
扩展的核心是包组件,它封装了所有必要的功能性和资产,包括动态链接库(DLL)和图像,成为一个单一的、可部署的单元。这种打包确保所有必需的文件都正确安装在 Visual Studio 环境中。对于需要与用户界面(UI)交互的扩展,包含菜单命令和工具窗口是必要的。这些元素使用 XML 定义,可以根据 IDE 内发生的特定条件或事件动态启用或禁用。
当扩展在项目级别运行时,项目系统集成变得至关重要。这涉及到与项目系统对象模型(PSOM)一起工作,它在 Visual Studio 中表示项目的结构和属性。提供代码生成和分析工具的扩展利用 Visual Studio 提供的 API 生成样板代码,重构现有代码或执行全面的代码分析。最后,扩展的成功往往取决于有效地利用 Visual Studio 提供的各种集成点,例如允许扩展响应特定 IDE 操作的事件处理器,如打开文档或构建解决方案。这些集成点使扩展能够通过响应 IDE 内的操作来自动化任务并增强用户体验。
除了构成 Visual Studio 扩展的核心组件外,Visual Studio Marketplace在生态系统中发挥着关键作用。这个平台作为扩展的主要分发中心,使开发者能够轻松地找到、安装和管理各种第三方工具。Visual Studio Marketplace 不仅简化了访问扩展的过程,而且还通过提供一个反馈和开发者与用户之间互动的空间来促进社区参与。
为了支持这些扩展的创建,Visual Studio 软件开发工具包(SDK)提供了所有必要的工具和文档。SDK 包括库、示例代码和全面的教程,旨在帮助我们开始构建自己的扩展。这个工具包对于导航扩展开发的复杂性并确保新工具与 Visual Studio 环境顺利集成至关重要。
在对 Visual Studio 扩展的基础组件及其支持生态系统有充分理解之后,你现在已经准备好迈出下一步:构建你的第一个扩展。在下一节中,我们将从头开始创建一个基本的 Visual Studio 扩展,展示如何利用 Visual Studio SDK 提供的工具和资源将你的想法变为现实。
构建你的第一个扩展
让我们创建一个简单的 Visual Studio 扩展,该扩展在工具菜单下添加一个新的菜单项。当点击时,这个菜单项将显示一个消息框。这个示例将指导我们设置一个基本的扩展项目。
在深入扩展开发之前,正确设置你的环境至关重要。第一步是确保我们安装了正确的工具。首先打开Visual Studio 安装程序并修改当前的 Visual Studio 安装。在安装程序中,我们需要检查 Visual Studio 扩展开发工作负载是否已安装。

图 14.1 – Visual Studio 扩展开发工作负载
这个工作负载包括 Visual Studio SDK 和其他构建扩展所需的必需工具。拥有这些组件是顺利开发过程的基础,确保你可以访问创建和测试我们的扩展所需的所有库、模板和资源。
要开始构建我们的扩展,请按照以下步骤操作:
-
首先打开 Visual Studio,为任何类型的项目选择创建新项目选项。
-
在项目创建窗口中,搜索VSIX 项目。这个模板专门用于创建 Visual Studio 扩展。一旦找到,选择模板并点击下一步继续。

图 14.2 – 创建新的 VSIX 项目
- 接下来,系统会提示我们为项目命名。选择一个能反映我们扩展功能的名字,以我们的示例为例,我们将选择MyFirstExtension,并指定你想要保存项目文件的路径。

图 14.3 – 配置 VSIX 项目
-
在我们配置了这些设置之后,点击创建以生成项目结构。这一步为我们的扩展设置了基本框架,使我们能够开始自定义和添加项目功能。
-
创建一个好的扩展的第一步是为我们的新功能添加一个入口点。最方便的方式是添加一个新的命令。在这里,我们将通过在项目节点上右键点击,选择添加 | 新项,然后在C#项 | 可扩展性下查找命令来利用 Visual Studio SDK 提供的项目模板。

图 14.4 – 添加新项 | 命令
在这个示例中,我们选择名字MyCustomTemplate。这个项目模板为我们第一个命令添加了所有需要的内容:
-
.vsct 文件,即 Visual Studio 命令表文件,是一个 XML 文件,用于在 Visual Studio 扩展中定义扩展添加到 Visual Studio 环境中的菜单、命令和其他 UI 元素的结构和行为。它充当扩展如何与 Visual Studio UI 集成的蓝图,指定菜单和按钮应放置的位置、它们应使用的图标以及它们在点击时的行为。
-
MyCustomCommand.cs 文件被添加到您的项目中;您需要用适当的代码替换其内容以定义所需的功能。目前,它定义了一个在执行时显示消息框的命令。
- 现在,当我们启动调试模式时,它将打开一个 Visual Studio 的实验实例。在这个实例中,我们将从扩展 | 管理扩展窗口检索我们安装的包。

图 14.5 – MyFirstExtension 已安装
此外,在工具菜单中,我们找到了调用 MyCustomCommand选项。目前,此命令仅简单地打开一个显示基本消息的消息框。

图 14.6 – 调用 MyCustomCommand
我们现在已经构建了我们的第一个扩展。让我们在下一节中探索我们可以添加的功能,以自定义我们的 Visual Studio 扩展。
高级扩展功能
正如我们所见,我们可以轻松地向 Visual Studio 的菜单中添加新命令,使我们能够与我们的 IDE 交互,甚至打开外部工具。在本节中,我们将探讨我们可以利用的预设模板来扩展 Visual Studio。
因此,如果我们回到添加项目窗口,通过右键单击项目节点并选择添加 | 新项…,我们可以找到按四个类别排序的 kickstart 命令。
首先,编辑器类别包括模板,允许修改和增强 Visual Studio 编辑器本身。这些修改可以从更改文本的突出显示到在编辑器面板内添加交互式元素。

图 14.7 – 添加新的编辑器项
以下是对编辑器类别内子类别的概述:
-
编辑器分类器:一个编辑器分类器项允许我们根据自定义规则对编辑器中的文本进行分类。这可以用于语法突出显示、识别代码中的特定模式,甚至提供关于编码标准的实时反馈。例如,我们可以创建一个分类器,用鲜艳的颜色突出显示所有待办事项注释,以确保它们引起开发者的注意。
-
编辑器边距:编辑器边距模板允许创建围绕编辑器面板的定制边距。这些边距可以显示与正在查看的代码相关的额外信息或控件。一个用例是实现一个显示代码文件迷你图的边距,使用户能够快速导航大型文件。
-
编辑器文本装饰:文本装饰允许在编辑器中对文本进行装饰。这可以包括下划线、删除线、背景颜色,甚至可以在文本中插入图像或图标。这允许我们为已弃用的方法添加红色波浪下划线,以视觉上指示它们不应被使用,例如。
-
编辑器视口装饰:类似于文本装饰,但专注于视口(编辑器的可见区域),视口装饰可以在编辑器内容之上叠加图形或 UI 元素。例如,在查看只读文件时,在编辑器上显示水印或横幅。
扩展包实际上是一组扩展的组合,旨在提供围绕特定主题或目的的全面功能集。创建扩展包允许开发者分发一套无缝协作的工具,增强特定开发场景的生产力并简化工作流程。
然后,工具箱类别包括为在 Visual Studio 中创建可以添加到 Windows Forms 或Windows Presentation Foundation(WPF)设计表面的控件而设计的模板。这些控件可以从简单的 UI 元素到封装特定功能的复杂组件不等。
此外,VSPackages代表了 Visual Studio 中更深层次的扩展性,允许创建可以修改或添加到 IDE 核心功能的扩展。这些包可以从简单的命令到复杂的工具窗口和服务不等。

图 14.8 – 添加新的 VSPackage 项目
在本节中,我们可以找到以下项目模板:
-
异步包:这为在 Visual Studio 扩展中创建异步操作提供了一个基础。这对于可能需要很长时间才能完成的操作特别有用,例如从外部服务获取数据或执行密集型计算。
-
命令:如前节所述,命令允许向 Visual Studio 菜单、工具栏或甚至上下文菜单中添加新操作。此模板便于创建可以与 IDE 或外部工具交互的命令,从而实现广泛的定制功能。
-
异步工具窗口:这与异步包类似,但专门针对在 Visual Studio 中创建异步工具窗口。这些工具窗口可以执行后台操作而不阻塞 UI,从而提高 IDE 的响应性。
-
工具窗口:此模板允许在 Visual Studio 中创建自定义工具窗口。工具窗口可以在 IDE 中停靠,并服务于各种目的,例如显示项目属性、搜索结果,甚至与您的流程相关的自定义控件和可视化。
此外,您还可以在 GitHub 上的官方 Visual Studio SDK 仓库中找到示例和样本:github.com/microsoft/VSSDK-Extensibility-Samples/tree/master。
记住,当使用这些模板开发扩展时,与其他开发一样,考虑最终用户的使用体验非常重要,确保添加的功能能够无缝集成到现有的 Visual Studio 环境中。测试和迭代是完善这些扩展并向开发者社区提供价值的关键。一旦我们的扩展经过定制和充分测试,下一步就是打包和部署它以供普遍使用。
部署和分享您的扩展
将 Visual Studio 扩展部署和分享给社区是扩展开发过程中的一个令人兴奋的步骤。这使我们能够为生态系统做出贡献,有可能改善全球成千上万的 Visual Studio 用户的使用体验。在本节中,我们将详细介绍部署和分享我们的扩展的指南,包括为增强安全性和可信度对 VSIX(一个 .vsix 文件包含一个或多个 Visual Studio 扩展)包进行签名。
一旦我们确保它经过彻底测试并准备好公开发布,我们就可以开始部署阶段。这包括在不同版本的 Visual Studio 上进行测试、处理边缘情况,并确保与各种项目类型和配置的兼容性。
首先,为了防止篡改并与最终用户建立信任,我们使用 Sign CLI 对我们的 VSIX 进行签名。您需要从受信任的 证书颁发机构(CA)购买代码签名证书。我使用 .NET CLI 安装 Sign CLI。请注意,在撰写本文时,Sign CLI 仍处于预发布阶段;因此,当我们需要获取最新版本时,我们需要包含 -prerelease 标签:
dotnet tool install sign --prerelease –global
安装后,Sign CLI 可以在开发者 PowerShell 实例中使用 sign code learn.microsoft.com/en-us/visualstudio/extensibility/dotnet-sign-cli-reference-vsix?view=vs-2022。
在对您的扩展进行签名后,下一步是将它部署到 Visual Studio Marketplace,这样全球的 Visual Studio 用户都可以访问。这个过程涉及几个关键步骤,以确保您的扩展得到适当的展示并准备好安装:
-
首先,在 Visual Studio Marketplace 上创建一个发布者账户。
-
如果您尚未这样做,请使用您的 Microsoft 账户登录并按照提示设置发布者配置文件。此账户将允许您在平台上管理和跟踪您的扩展。
-
接下来,通过导航到 发布者 控制台并选择 新建扩展 选项(这里是 Visual Studio 市场控制台的链接:
marketplace.visualstudio.com/manage/createpublisher?managePageRedirect=true)来创建一个新的扩展。在这里,您需要提供有关您扩展的基本信息,包括标题、描述以及相关的视觉元素,如图标和截图。这些元素有助于潜在用户了解您的扩展提供的内容。 -
一旦填写完详细信息,请上传您已签名的 VSIX 包。Visual Studio 市场将自动验证该包及其数字签名,确保一切就绪后再继续。
-
上传后,提交您的扩展以供审查。微软将仔细评估您的提交,以确保其符合市场政策和指南。
此审查过程对于维护用户可用的扩展的质量和安全至关重要。
最后,在批准后,您的扩展将在 Visual Studio 市场发布。然后,它将可以通过 Visual Studio IDE 直接安装,或从 Visual Studio 市场网站下载,让全球的开发者都能从您的贡献中受益。
摘要
在我们结束关于 Visual Studio 扩展开发的这一章时,您已经获得了创建、精炼和分发您自己的强大扩展所需的知识和技能。从理解核心架构到构建您的第一个扩展,再到探索高级功能,您已经学会了如何增强 Visual Studio 以更好地满足您和您团队的需求。通过掌握部署和共享过程,您现在可以贡献给更广泛的开发者社区,提供可以简化工作流程并提高生产力的工具。
在这个坚实的基础之上,我们现在准备过渡到本书的最后一章。在这一章的结尾,我们将深入探讨 NuGet 包的创建世界,您将学习如何打包和分发可重用的代码库。
第十五章:为社区创建和发布强大的 NuGet 包
在本章中,我们将开始一段全面探索 NuGet 和包管理的旅程,这是现代 .NET 开发的一个基本方面。无论你是经验丰富的开发者还是新手,理解 NuGet 都能提升你管理依赖项和简化工作流程的能力。
我们将从介绍 NuGet 的基础知识开始,涵盖它是什么以及为什么它是 .NET 生态系统中的基石。你将获得创建第一个 NuGet 包的实用见解,包括设置项目、打包你的代码和生成 .nupkg 文件的动手经验。随着我们的进展,我们将掌握版本管理和依赖项管理,这些是确保你的包兼容和更新的关键技能。然后,我们将探讨发布和分发你的包的过程,确保我们的工作能够触及正确的受众。最后,我们将深入研究高级功能和最佳实践,从针对特定平台到包含预发布版本。
在本章中,我们将涵盖以下主要主题:
-
介绍 NuGet 和包管理
-
创建你的第一个 NuGet 包
-
版本管理和依赖项管理
-
发布和分发
-
高级 NuGet 功能
到本章结束时,你将具备创建、管理和分发 NuGet 包的有效知识和技术,这将使你能够自信地贡献更广泛的 .NET 社区。
技术要求
在编写本章时,我使用了以下版本的 Visual Studio:
-
Visual Studio Enterprise 2022 版本 17.12.0
-
预览 1.0
本章的代码文件可以在 github.com/PacktPublishing/Mastering-Visual-Studio-2022/tree/main/ch15 找到。
NuGet 和包管理简介
在本节开头,我们将为后续内容打下基础。我们将探讨 NuGet 是什么,它在 .NET 生态系统中的重要性,以及它如何改变开发者共享和重用代码的方式。
NuGet 是一个免费且开源的包管理器,专为 Microsoft 开发平台设计,包括 .NET。在其核心,NuGet 作为一种共享代码和加速开发过程的机制。它允许开发者创建封装功能、库或框架的包,并通过 NuGet 仓库进行分发。
NuGet 的重要性在于其简化将第三方库纳入项目、管理依赖项并保持其更新的能力。这种方法显著降低了与手动依赖项管理相关的复杂性,这在 .NET 开发中曾经是一个常见的挑战。
NuGet 生态系统庞大且动态。其核心是官方的 NuGet 仓库(nuget.org),它托管了由社区贡献的数千个包。然而,NuGet 不仅限于公共仓库;它还支持私有源,允许组织控制对内部包的访问。
NuGet 最显著的优点之一是它简化了依赖关系管理。使用 NuGet,开发者不再需要手动下载和安装库。相反,他们只需在项目中添加对所需包的引用,NuGet 就会负责下载和安装正确的版本。
为了有效地创建和消费包,正确设置开发环境至关重要。我们可以通过顶级工具栏访问包管理器的一般配置 – 工具 | NuGet 包管理器 | 包 管理器设置 。

图 15.1 – NuGet 包管理器选项
这里有一些关于可用选项的详细信息:
-
包还原:在此处勾选两个复选框可以确保在构建解决方案时自动还原 NuGet 包。这很重要,因为它保证了所有必要的包都可用,即使它们没有被包含在源控制中,从而避免了构建过程中的包缺失问题。
-
绑定重定向:这是一个用于解决程序集之间版本冲突的机制。当你在引用多个库的 .NET 项目上工作时,经常会遇到不同库依赖于同一程序集的不同版本的情况。这可能导致由于版本冲突而导致的运行时错误。你可以选择跳过那些库,但在你无法控制第三方库的版本依赖但需要确保应用程序兼容性的场景中,这尤其有用。
-
包管理:在这里,我们可以选择包管理文件的默认格式。我们还可以选择在安装第一个包时选择格式。
-
清除所有 NuGet 存储:全局 NuGet 缓存存储了我们下载或安装的包的副本。清除此缓存确保我们的开发环境从头开始,没有任何可能损坏或过时的包。这有助于解决与包相关的问题,并确保我们使用的是干净、最新的包。另一种实现此目的的方法是以管理员身份打开命令提示符并运行 nuget locals all - clear 命令。
既然我们已经了解了 NuGet 的基本知识和其重要性,让我们继续探讨实际操作方面。现在是时候卷起袖子,开始创建我们自己的 NuGet 包了。
创建您的第一个 NuGet 包
在这里,我们将直接进入行动。我们将逐步介绍从头创建简单 NuGet 包的过程,涵盖从初始设置到发布的每个步骤。这种动手经验将帮助巩固上一节中介绍的概念,并为您准备更高级的包创建。
让我们进一步分解这个过程。首先,我们将在 Visual Studio 中创建一个新的 .NET Standard 库项目。这种类型的项目非常适合创建 NuGet 包,因为它与多个 .NET 框架兼容。让我们开始以下步骤:
-
打开 Visual Studio 并选择 新建项目。
-
对于此示例,在 C# 部分下选择 .NET Standard。
-
命名项目(例如,MyFirstPackage)并点击 确定。
接下来,我们将通过向项目中添加一些示例代码来编写包内容。为此示例,让我们创建一个简单的实用类,用于在摄氏度和华氏度之间转换温度:
using System;
namespace MyFirstPackage
{
public static class TemperatureConverter
{
public static double ConvertCelsiusToFahrenheit(
double celsius)
{
return (celsius * 9 / 5) + 32;
}
public static double ConvertFahrenheitToCelsius(
double fahrenheit)
{
return (fahrenheit - 32) * 5 / 9;
}
}
}
现在我们有了代码,我们需要为打包做准备:
-
在 解决方案资源管理器 窗口中右键单击项目。
-
选择 添加 | 新建文件夹。
-
将文件夹命名为 lib。
-
将 TemperatureConverter.cs 文件移动到这个文件夹中。
在我们的项目准备就绪后,我们现在可以创建 NuGet 包:
-
在 解决方案资源管理器 窗口中右键单击项目。
-
从上下文菜单中选择 打包。
这将在 bin/Debug 文件夹中生成一个 .nupkg 文件。
让我们验证我们的包是否已成功创建:
-
在 bin/Debug 文件夹中定位 .nupkg 文件。
-
双击文件以查看其内容。
-
检查包是否包含包含我们的 TemperatureConverter.cs 文件的 lib 文件夹。
现在我们已经创建了我们第一个 NuGet 包,让我们花点时间反思我们所取得的成就。我们从没有任何包变成了一个功能齐全的包,我们可能与他人分享。现在我们已经做到了这一点,有一个重要的方面我们需要解决——我们如何确保我们的包保持稳定,不会在其他人的项目中引起问题?
版本控制和依赖关系管理
版本控制对于保持兼容性和负责任地管理更新至关重要。正确处理包之间的依赖关系同样重要,因为它确保您的包能够与其他项目中的包无缝工作。
版本控制是将唯一标识符分配给我们的包的不同版本的过程。这是向用户传达自上次发布以来您的包发生了多少变化的一种方式。版本控制有两种主要方法:
-
语义版本控制:
-
主版本:破坏性更改
-
次要版本:新增功能
-
补丁版本:错误修复
例如 1.0.0, 1.1.0, 1.2.0 等等
-
-
基于日期的版本控制:
- 使用日期来表示包发布的时间
例如 2023.01.01.0
虽然基于日期的版本更简单,但语义版本通常更受欢迎,因为它提供了关于包历史的更多有意义信息。
我们可以通过导航到我们的项目的属性来轻松定义我们的包版本:
-
在解决方案资源管理器窗口中,右键单击项目,
-
选择属性。
-
前往包选项卡。

图 15.2 – 包属性
在这里,我们定义了我们的包的 1.0.1 版本;如果我们再次打包项目,它将生成一个带有新定义版本的新.nupkg文件。
依赖管理涉及指定您的包依赖于哪些其他包。这对于确保我们的包在各种环境中正确运行至关重要。
在 NuGet 包中声明依赖有两种方式:
-
直接依赖 :
-
指定您依赖的包的确切版本。以下是一个示例:
<dependencies> <group targetFramework="netstandard2.0"> <dependency id="System.Collections" version="4.3.0" /> </group> </dependencies>
-
-
范围依赖 :
-
指定可接受版本的范围。以下是一个示例:
<dependencies> <group targetFramework="netstandard2.0"> <dependency id="Newtonsoft.Json" version="[12.0,13.0)" /> </group> </dependencies>
-
范围依赖允许灵活性,同时仍然保持对使用版本的一定控制。
有效的版本管理和依赖管理是软件开发中的基本实践。在整个包的生命周期中坚持选择版本策略对于保持一致性至关重要。
明确传达这种策略,特别是通过如README.md文件这样的文档,有助于确保所有利益相关者都理解这种方法。保持依赖项更新同样重要,因为对您依赖的包的定期更新可以防止兼容性问题并增强安全性。
对不同版本的依赖进行彻底测试是必要的,以尽早识别潜在冲突。此外,考虑传递依赖也很重要——这些间接依赖可能会影响您的包的行为,以保持整体稳定性和可靠性。
现在我们已经涵盖了版本管理和依赖管理的要点,让我们将注意力转向将我们的包推向世界的下一个关键步骤——发布和分发。这是我们将我们的辛勤工作提供给他人并可能成为.NET 包丰富生态系统一部分的地方。
发布和分发
发布您的 NuGet 包可以让整个.NET 社区或您整个组织访问它。本节将指导您将包发布到官方 NuGet 库,以及替代分发方法。
让我们详细探讨如何发布到官方 NuGet 库:
-
在
www.nuget.org/上登录您的账户。 -
点击创建新包并填写所需详细信息。
-
上传. nupkg文件。
-
填写包元数据(描述、标签等)。
-
审查并提交包。
虽然官方图库是分发包最广泛认可的方法,但在某些情况下,其他分发方法可能更合适。例如,私有资源库对于公司内部或团队特定的包特别有用。这些资源库可以托管在 Azure DevOps、GitHub 或甚至自托管服务器上,为组织内部的包分发提供了一个安全和受控的环境。本地资源库是另一个选项,非常适合测试和开发环境。这些可以直接在您的本地机器上设置,或集成到 CI/CD 管道中,在开发过程中提供方便的包管理方式。对于那些需要更多控制的人来说,自定义服务器允许对包分发进行细粒度管理,尽管这也带来了托管基础设施和持续维护的额外责任。
私有资源库为组织内部或特定开发人员群体内部使用的 NuGet 包提供了一个安全和受控的环境。与任何人都可以访问的公共资源库(如 nuget.org)不同,私有资源库仅限制授权用户访问。这对于专有软件组件、测试版本或需要遵守特定安全策略的情况尤其有用。
JFrog Artifactory 是管理二进制存储库中最受欢迎的工具之一,包括 NuGet 包。它支持公共和私有 NuGet 资源库,使其成为组织建立自己的 NuGet 存储库基础设施的绝佳选择。
下面是如何在 Artifactory 中设置私有 NuGet 资源库的详细信息:
-
安装 Artifactory:首先,您需要在您的服务器或云环境中安装 JFrog Artifactory。遵循 JFrog 提供的官方安装指南。
-
创建新的存储库:一旦 Artifactory 启动并运行,登录到管理控制台。导航到 存储库 部分,并选择创建新的存储库。选择 NuGet 作为包类型。
-
配置存储库设置:根据您的需求指定存储库密钥、布局和其他设置。对于私有资源库,请确保存储库不可公开访问。
-
设置访问控制:定义谁可以访问您的新 NuGet 资源库。您可以创建不同团队或项目的组,并分配适当的权限。
-
发布包:设置好存储库后,您现在可以将其发布到其中。使用 nuget push 命令或将其集成到您的 CI/CD 管道中以自动化此过程。
当与 Artifactory 和其他私有 NuGet 资源库一起工作时,我们必须在 Visual Studio 中设置一个 NuGet 源,以便在包还原过程或向项目中添加新包时指定 NuGet 包的检索位置。
这是我们在 Visual Studio 中设置 NuGet 源的方法:
-
转到工具 | NuGet 包管理器 | 包管理器设置。
-
从左侧导航菜单中选择包源。
要添加新的包源,请点击包源窗口右上角的绿色加号(+)按钮。

图 15.3 – 添加新的包源
- 在名称和源文本框中填写以适应要添加的期望的 NuGet 源。

图 15.4 – 配置新的包源
- 然后,通过点击更新按钮验证源。
添加并配置您的包源后,您可以通过尝试还原包或搜索 Visual Studio 中的包来验证它是否正常工作。转到工具 | NuGet 包管理器 | 管理解决方案的 NuGet 包…,然后您可以使用右上角的选择框选择您想要使用的包源。

图 15.5 – 选择包源
在我们结束创建和发布 NuGet 包的过程时,值得花点时间来欣赏 NuGet 的强大和灵活性。从它作为简单的包管理器的朴素起源到目前作为.NET 开发基石的地位,NuGet 一直在发展和改进。
高级 NuGet 功能
在本节的最后,我们将探讨 NuGet 的一些更高级功能,例如目标框架、预发布版本和自定义脚本,并讨论包开发的最佳实践。这些知识将帮助您创建更健壮、灵活和可维护的包。
目标框架
目标框架允许我们指定您的包支持哪些.NET 平台,确保在各种环境中保持兼容性。此功能通过仅允许在针对支持框架的项目中安装您的包来帮助防止兼容性问题。
在创建 NuGet 包时,您可以在.csproj或.nuspec文件中定义多个目标框架。这种设置使 NuGet 可以为每个框架打包单独的二进制文件,确保当可用时,您的包利用平台特定的功能。
这里有一个配置示例:
<PropertyGroup>
<TargetFrameworks>net46;netstandard2.0</TargetFrameworks>
</PropertyGroup>
此配置表示项目针对.NET Framework 4.6 和.NET Standard 2.0,允许在不同环境中实现最佳兼容性和功能。
预发布版本
预发布版本是分发尚未准备好用于生产使用的包的一种方式。这些版本通常用于 beta 测试、发布候选或夜间构建。
为了允许软件包作者分发他们认为不稳定或最终的软件包版本,消费者可以选择安装这些预发布版本以提前测试新功能或错误修复。
预发布版本通过在版本号后附加一个后缀来表示,后跟一个连字符。常见的后缀包括-alpha、-beta、-rc(发布候选)和-preview。消费者需要明确选择才能接收预发布软件包,通常通过他们的软件包管理器客户端中的设置来完成。
这里是一个配置- beta 版本的示例:
<Version>1.0.0-beta1</Version>
这表明该软件包是 1.0.0 的 beta 版本,适合测试但不推荐用于生产使用。
定制脚本
NuGet 支持在安装或卸载软件包时执行 PowerShell 脚本。此功能可用于各种目的,例如修改项目文件、注册组件对象模型(COM)组件或执行其他设置任务。
定制脚本自动化了在安装或卸载软件包时需要执行的任务,减少了消费者的手动步骤并确保了一致性。
作为软件包作者,我们可以在我们的软件包中包含 PowerShell 脚本,NuGet 将在适当的时候执行这些脚本。有几种类型的脚本,包括init.ps1(每次解决方案运行一次)、install.ps1(每次安装软件包时运行)和uninstall.ps1(在卸载软件包时运行):
<packageTargetFallback
Condition="'$(OS)' == 'Windows_NT'">
win7-x64-msvc2015
</packageTargetFallback>
<script
src="img/precompile.js"
condition="$([MSBuild]::GetTargetPath(
'$(ProjectDir)tools\precompile.js')) != ''"
/>
此配置指定了一个后备目标框架,并包含一个将在特定条件下执行的定制脚本(precompile.js)。请注意,定制脚本现在使用较少,尤其是在.NET Core 和.NET Standard 的发展过程中,但为了向后兼容,它们仍然得到支持。
通过利用 NuGet 的这些高级功能,我们可以创建更复杂和灵活的软件包,更好地满足不同环境和开发阶段用户的需求。
摘要
在本章中,我们探讨了.NET 生态系统内 NuGet 和软件包管理的关键方面。我们首先了解了什么是 NuGet 以及为什么它是现代开发中管理依赖关系的关键工具。我们学习了如何创建我们的第一个 NuGet 软件包,包括设置项目、编写必要的代码并将其打包成. nupkg文件。
我们随后深入探讨了版本控制和依赖关系管理,强调了语义版本控制的重要性以及在不同版本之间保持兼容性的策略。本章还涵盖了发布和分发 NuGet 软件包的步骤,无论是官方 NuGet 库还是通过其他方法,确保您的软件包对他人可访问。
最后,我们探讨了高级功能和最佳实践,例如针对特定平台,使用预发布版本,以及集成自定义脚本。现在,你已经全面了解了如何创建、管理和分发 NuGet 包,并为你提供了增强 .NET 开发实践的工具。
随着《精通 Visual Studio》的结束,我们经历了一系列对任何在 .NET 和 Visual Studio 生态系统内工作的严肃开发者至关重要的高级技术、工具和最佳实践。这本书为你提供了强大的技能和知识,使你成为一个更高效、多才多艺和创新的开发者。无论你是在构建智能应用、优化性能,还是为开发者社区做出贡献,你所获得的技能将继续推动你在软件开发世界中的成功。


浙公网安备 33010602011771号