-NET-解决方案架构指南-全-
.NET 解决方案架构指南(全)
原文:
zh.annas-archive.org/md5/6ba06be74d70f4309c21b4600fb74f93译者:飞龙
前言
在我们快速发展的数字化世界中,由数字化转型驱动,解决方案架构师是具有特定技能集和广泛技术专长的最重要专家,他们能够在业务需求和技术解决方案之间取得平衡。本书的目的是通过实践方法让你对 .NET 解决方案架构有一个广泛的理解,帮助你成为一名有效的解决方案架构师。
本书涵盖了软件开发生命周期(SDLC)的原则、.NET 解决方案架构师的职责和成为一名优秀的 .NET 解决方案架构师的条件。随着你阅读章节的深入,你将了解解决方案架构的关键原则以及如何设计解决方案、探索设计层和微服务。
你将通过揭示设计和构建数字解决方案的现代架构模式和技术的学习之旅完成你的学习。
在本书结束时,你将学会如何使用 ASP.NET Core 和 Microsoft Azure 架构你的现代网络解决方案,并准备好使用 Azure DevOps 自动化你的开发生命周期。
本书面向的对象
本书面向中级和高级 .NET 开发人员和软件工程师,他们希望提升自己的职业生涯并扩展对解决方案架构和设计原则的知识。寻找构建大型 .NET 解决方案技巧和窍门的初学者或中级解决方案架构师也会发现本书有用。
本书涵盖的内容
第一章, 软件开发生命周期原理,帮助你理解软件开发生命周期的概念和原则是规划软件产品的良好起点。本章旨在解释 SDLC 的概念、阶段和方法。
第二章, 团队角色与职责,主要关注典型软件开发团队中的主要角色及其相应的职责。一个软件项目成功的关键因素之一是确保开发团队的关键利益相关者都到位。项目的成功也取决于团队协作的好坏。
第三章, 成为一名优秀解决方案架构师的条件是什么?,更详细地阐述了成为一名优秀解决方案架构师所需具备的个人素质。
第四章, 设计解决方案架构,通过探讨解决方案架构的关键原则和推荐用于设计中到大型解决方案的最流行的统一建模语言(UML)图来关注解决方案架构实践。
第五章, 探索架构设计模式,讨论了现代架构模式及其示例用例。此外,我们还将解释应采用哪些标准来为我们的软件解决方案选择正确的架构模式。
第六章, 架构考虑因素,探讨了设计质量属性以及如何正确规划缓存、异常处理和部署。
第七章, 保护 ASP.NET Web 应用程序,探讨了在设计解决方案时需要考虑的安全因素,并在此背景下查看最佳实践。
第八章, 在解决方案架构中进行测试,探讨了不同类型的测试,包括单元测试、压力测试和自动化测试。
第九章, 使用 ASP.NET Core 和 Azure 构建现代 Web 解决方案,帮助您学习如何使用 ASP.NET Core 构建跨平台现代 Web 解决方案,以充分利用其功能。在 Azure 中托管使用 ASP.NET Core 构建的应用程序,与传统替代方案相比具有许多竞争优势。ASP.NET Core 优化了现代 Web 应用程序开发实践和云托管场景。
第十章, 设计和实现 Microsoft DevOps 解决方案,帮助您学习如何利用 Azure DevOps 通过现代软件开发实践构建、测试和部署应用程序。此外,我们将了解如何管理源代码控制,并探索使用 Azure Artifacts 的包管理,以及理解持续集成/持续部署实践。
为了最大限度地利用这本书
在您开始阅读本书之前,应确保满足以下一些要求:
-
您应该是一个中级或高级的 .NET 开发者。
-
您应该具备一些关于 Microsoft Azure 的基本知识。

下载彩色图像
我们还提供了一个包含本书中使用的截图和图表彩色图像的 PDF 文件。您可以从这里下载:static.packt-cdn.com/downloads/9781801075626_ColorImages.pdf。
使用的约定
本书使用了多种文本约定。
文本中的代码: 表示文本中的代码单词、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟 URL、用户输入和 Twitter 用户名。以下是一个示例:"通过在控制器类或非匿名操作中添加 [Authorize] 属性,在 MVC 中应用授权相当简单。"
代码块应如下设置:
[Authorize(Users = "john,tim")]
public IActionResult EditContent()
{
return View();
}
任何命令行输入或输出都应如下编写:
Request URL:http://TheWebsiteUrl/register
Request Method:POST
Status Code:200 OK
firstname:John
粗体:表示新术语、重要词汇或您在屏幕上看到的词汇。例如,菜单或对话框中的单词会以粗体显示。以下是一个示例:“如图所示,我们首先需要设置应用程序中使用的域名。”
小贴士或重要注意事项
看起来是这样的。
联系我们
我们欢迎读者的反馈。
一般反馈:如果您对本书的任何方面有疑问,请通过电子邮件发送至 customercare@packtpub.com,并在邮件主题中提及书名。
勘误:尽管我们已经尽最大努力确保内容的准确性,但错误仍然可能发生。如果您在这本书中发现了错误,我们将不胜感激,如果您能向我们报告,我们将不胜感激。请访问 www.packtpub.com/support/errata 并填写表格。
盗版:如果您在互联网上发现我们作品的任何形式的非法副本,我们将不胜感激,如果您能提供位置地址或网站名称,我们将不胜感激。请通过电子邮件发送至 copyright@packt.com 并附上材料的链接。
如果您有兴趣成为作者:如果您在某个领域有专业知识,并且对撰写或参与书籍的编写感兴趣,请访问 authors.packtpub.com。
分享您的想法
一旦您阅读了《.NET 解决方案架构》,我们很乐意听到您的想法!请点击此处直接进入此书的亚马逊评论页面并分享您的反馈。
您的评论对我们和科技社区都很重要,并将帮助我们确保我们提供高质量的内容。
第一部分:理解解决方案架构师的责任
在本节中,我们将探讨软件开发生命周期(SDLC)的不同阶段,并了解流行的 SDLC 模型如 Scrum、螺旋和 DevOps 之间的区别。然后,我们将学习典型软件开发团队中的层级结构以及每个成员(包括解决方案架构师)应承担的责任。
在本节的后面部分,我们将探讨每个解决方案架构师都应该具备的一些基本软技能,并了解一些应避免的常见陷阱。
本节包括以下章节:
-
第一章,软件开发生命周期原则
-
第二章,团队角色和责任
-
第三章,什么使解决方案架构师有效?
第一章:第一章:软件开发生命周期的原则
在现代数字工作场所,.NET 解决方案架构师在软件开发生命周期中的作用变得越来越关键。拥有能够设计和构建强大且高效解决方案的技术领导者和解决方案创造者,是成功交付产品的关键因素。
本书将突出您作为.NET 专业开发者需要了解的基础知识,以便在这个不断增长和快速变化的领域中成为一名有效的解决方案架构师。
理解软件开发生命周期(SDLC)的概念和原则是规划软件产品的良好起点。本章旨在解释 SDLC 的概念、阶段和现代方法。
在本章中,我们将涵盖以下主题:
-
理解什么是软件开发生命周期(SDLC)
-
探索不同的软件开发生命周期(SDLC)阶段
-
熟悉流行的 SDLC 模型
在本章结束时,您将能够描述软件开发生命周期的阶段,并解释流行的 SDLC 模型之间的区别,例如Scrum、螺旋模型和DevOps。
理解软件开发生命周期
在当今的数字世界中,每家公司都希望在一个较短的时间内交付高质量的软件产品,这意味着开发团队的效率和速度是改变游戏规则的因素。为了实现这一目标,公司必须应用一系列定义明确的活动和结构化阶段,这些活动和阶段定义了软件开发生命周期,也称为SDLC。
软件开发生命周期(SDLC)是一种工作方法和最佳实践的方法论,旨在简化软件开发过程,使其更加高效,确保最终产品在项目预算内按时交付,并且完全符合客户的期望。
软件开发生命周期(SDLC)有不同的变体和模型,例如瀑布模型、螺旋模型和敏捷模型。它们在大多数软件开发组织中都很受欢迎,并且被广泛使用。选择正确的模型主要取决于项目的规模和其他因素。在接下来的几节中,我们将详细探讨这些模型,以帮助您决定哪种模型适合您的团队和项目。
下面是 SDLC 过程中定义的六个阶段:

图 1.1:软件开发生命周期的六个阶段
我们刚刚概述了软件开发生命周期及其重要性。在下一节中,我们将探讨软件开发生命周期过程的各个阶段。
探索不同的软件开发生命周期(SDLC)阶段
SDLC 中的主要活动有哪些? 无论你选择哪种模型来实施你的产品,都存在六个不同的阶段,这些阶段被认为是大多数现有模型中的常见阶段。然而,根据模型的不同,这些阶段可以是顺序执行或并行执行。通过执行这一系列阶段,预期可以避免典型的和昂贵的陷阱,并实现以下目标:
-
成本降低
-
整体质量提升
-
缩短生产时间
-
优秀的客户满意度
让我们探索这些阶段,因为理解它们对于解决方案架构师非常重要,他将参与所有这些阶段。另一方面,了解这些阶段对于组织并促进产品的开发,以及使整个开发过程更加透明也是必要的。我们将在以下各节中了解每个阶段。
规划和需求分析
由于需求分析是第一个阶段,它是 SDLC 中最重要和最基本阶段。此阶段从识别客户的利益相关者开始,然后进行多次会议和研讨会,以定义期望并收集需求。
此阶段由业务分析师、项目经理和团队的高级技术成员执行。他们与客户进行会议和研讨会,以收集所有功能和非功能需求,例如构建产品的目的、它将解决的问题、它将如何提高工作效率、它将在功能和服务的哪些方面包含,目标受众或最终用户是谁、识别用户旅程、详细用例和测试用例、硬件要求、备份策略和故障转移流程。
规划是创建一个详细但高级的计划的过程,说明每个项目模块或任务如何以及何时开发。目标是确定任务及其依赖关系,以及每个任务的预期输出。这应该与需求分析中定义的客户期望保持一致。
在此阶段之后,团队中的每个人都应该对项目的范围有一个清晰的了解,包括其预算、资源、截止日期,以及可能的风险和质量保证需求。这将与客户共享,以使他们对项目的执行保持一致,并为他们提供更好的透明度。
让我们看看在执行需求分析阶段时通常使用的不同技术和活动:
-
用例:这是一种广泛使用的有效技术,用于捕获用户需求。它允许我们识别系统要实现每个功能的可能流程,以及它将如何与最终用户交互。您可能会想知道,“我应该写多少个用例?”这个问题一开始可能听起来很难,但这个简单问题的答案是写下尽可能多的用例,以确保您涵盖了系统应包含的所有可能动作和功能。
以下是用例的常见部分:
a. 用例名称
b. 摘要描述
c. 参与者
d. 前置条件
e. 后置条件
f. 级别
g. 利益相关者
-
业务流程建模符号(BPMN):这是全球范围内用于创建使用符号和元素描述和记录业务序列的图表。如果您正在实施业务自动化流程或产品包含如审批周期等业务工作流,则建议使用此技术。
这里是 Visio 中 BPMN 图的基本形状:

图 1.2:BPMN 图的基本形状
- 统一建模语言(UML):UML 用于创建流程图和图表,以可视化和记录软件组件,如类和接口。UML 是一种良好的设计实践,也是创建面向对象软件的非常有用的技术;它帮助软件开发人员对任何复杂的软件架构进行建模和沟通:

图 1.3:示例类图
- 流程图技术:这是另一种用于描述顺序和逻辑流程不同步骤的图形表示方法。在下面的图中,我们有一个示例流程图,用于结账过程。绿色框表示用户在结账并收到确认之前尝试将项目添加到结账购物车时的起点。红色框代表流程的结束;即,其完成:

图 1.4:示例流程图
- 数据流图(DFD):一图胜千言。您可以使用 DFD 可视化表示数据在系统中的流程或服务中的流动方式。此图用于识别和描述输入数据及其如何通过系统移动到其存储位置并形成输出数据。以下是一个描述采购订单流程数据流的示例 DFD 图:

图 1.5:示例数据流图
- 角色活动图(RAD):这是对系统中每个可能动作的角色导向表示。它用于轻松描述和可视化参与执行系统中每个流程或服务的不同角色。以下是一个描述自动柜员机交易并展示每个关键角色所完成步骤的样本角色活动图:

图 1.6:样本角色活动图
-
甘特图:这些用于项目管理,以协助规划和调度各种规模的项目。它们提供了任务、交付日期以及每个任务的顺序和依赖关系的视觉表示。
这使得执行计划对客户来说更加简化和透明。以下是一个表示项目计划的样本甘特图。任务根据特定上下文分组,并通过前驱列、开始日期和结束日期链接:

图 1.7:样本甘特图计划
- 差距分析:这是一种帮助比较系统当前实际结果与客户在项目早期阶段期望的技术。它有助于指出系统中任何缺失的战略能力或特性。它还应推荐你可以采取的改进方式,以帮助客户实现他们的初始目标。以下是一个可以用于进行差距分析练习的样本模板:

图 1.8:样本差距分析模板
- 构建原型:构建一个原型,或一个最小可行产品(MVP)模型,将使最终用户对产品最终版本的外观有一个概念,一旦所有功能都得到实现。使用这种技术,你可以识别在实际上实施产品时可能遇到的任何可行性挑战。
在执行分析时,考虑将需求分为以下三个类别:
-
功能需求:这些代表系统所有详细的功能和特性。它们对于开发团队来说非常重要,以便了解要实现什么,对于客户的利益相关者来说也非常重要,以帮助他们就产品的最终结果达成一致。
-
操作需求:这些定义了产品正常运行所需的场景和性能衡量标准,以及相关的需求,以符合客户的期望。这包括以下内容:
a. 建立关键和期望的用户性能
b. 定义约束
c. 建立所需的基础设施
d. 建立有效性衡量标准
-
技术需求:这些描述了必须满足的技术部分,以便轻松且成功地部署产品,并使其按照客户的期望具有良好性能。这包括将要使用的技术、技术架构、硬件、第三方集成、测试和部署计划。
在这个阶段应考虑以下几点:
-
在需求收集阶段的主要挑战之一是,客户的每个利益相关者都从自己的角度看待产品。为了项目的成功,请考虑倾听并捕捉所有用户的观点,并在用户故事或用例中记录下来。这将帮助您确定产品的完整面貌以及它将提供哪些功能。
-
在与客户的第一次会议中,尝试识别不同的利益相关者,并讨论工作范围,以便让所有各方都清楚。之后,您将需要与所有利益相关者会面,收集详细的需求。在这些研讨会中,确保您将所有讨论都保持在设定的范围内。这对于保持需求与业务需求一致,以及避免添加产品从未预期提供的功能非常重要。
到目前为止,我们已经探讨了我们可以用于规划和执行需求分析研讨会不同活动和技术的不同方法,这对于项目的成功至关重要。在下一节中,我们将学习如何记录需求。
定义需求
在完成需求分析研讨会之后,下一步是记录之前收集到的所有信息,以定义产品需求。通常,这一活动的输出结果是软件需求规格说明书(SRS)文档,它包含了在整个项目所有阶段中需要设计和开发的所有详细需求,从项目开始到结束,直到交付所需的产品。这个 SRS 成为将用于开发产品的需求合同。它将解决客户的所有业务需求。
一旦 SRS 文档被所有参与项目的各方最终确定并审查,请确保将其发送回关键利益相关者或关键利益相关者的代表,以签署它。签署 SRS 的目的是同意文档中呈现和定义的需求是清晰的,并反映了在分析研讨会中讨论的业务需求。这种由所有参与方表达的形式承诺,在项目生命周期中将发挥关键作用,以确保项目在实施过程中不会出现范围蔓延。
重要提示:
在项目管理中,范围蔓延(或需求蔓延)指的是在项目启动后,客户持续要求更改并添加新功能到产品中的情况。结果,项目的范围将持续增长,这将影响交付时间和产品的最终成本。这种情况不应发生,为了防止它,你必须确保所有业务需求(即项目的范围)都非常详细且正确定义,并且客户已正式承诺工作范围。
一个 SRS 文档的基本大纲可能看起来像这样:
-
引言
1.1 目的
1.2 预期受众
1.3 预期用途
1.4 范围
1.5 定义和缩写
-
总体描述
2.1 用户需求
2.2 设计和实现约束
2.3 假设和依赖关系
-
系统特性
3.1 功能性要求
-
外部接口要求
4.1 用户界面
4.2 软件接口
4.3 硬件接口
-
非功能性要求
5.1 性能要求
5.2 安全要求
5.3 软件质量属性
随意使用这个大纲并根据您的需求进行修改,但请记住,本文档应描述产品需要实现的功能,以及技术规范。因此,它应该是简单、易于阅读和理解,以便项目利益相关者。在下一节中,我们将了解架构设计阶段。
架构设计
我们将如何构建产品? 这是一个关键问题,尤其是如果你正在构建一个复杂或大规模的产品,该产品将被广泛用户使用。
为了回答这个问题,我们需要开始架构设计阶段,这个阶段包括将前几个阶段中定义和记录的软件规范转换为一个称为架构设计的抽象设计规范计划。
这个阶段的开端是审查 SRS 文档,并理解需求中的每一个细节。这将帮助你创建最佳的架构设计,确保你交付高质量的产品。技术团队有责任在设计规范文档(DDS)中记录他们的设计。本文件的预期受众是设计师、软件开发人员和 QA 测试人员。
本文档的目的是提供一个全面的架构概述,并描绘系统组件的所有技术细节。更具体地说,它应该包括以下内容:
-
系统架构、组件、类及其属性和方法
-
数据库的设计,包括表和字段的定义,以及表之间的关系
-
图形界面设计
-
硬件或软件环境
-
最终用户环境
-
安全要求
-
性能要求和容量限制
本 DDS 由所有关键技术利益相关者进行审查。基于设计模块化、性能、安全性、容量限制、风险、预算和时间限制等因素,选择最佳设计方法来构建产品。
一个 DDS 文档的基本大纲可能看起来像这样:
-
引言
1.1 目的
1.2 范围
1.3 设计目标
1.3.1 可维护性
1.3.2 优化性能
1.3.3 设计友好
-
系统概述
2.1 算法
2.2 使用的技术
2.3 架构图
2.4 数据库设计
-
设计考虑
3.1 假设和依赖
3.2 一般约束
3.3 目标和指南
3.4 开发方法
-
架构策略
4.1 策略-1 名称或描述
4.2 策略-2 名称或描述
4.3 ...
-
系统架构
5.1 组件-1 名称或描述
5.2 组件-2 名称或描述
5.3 ...
-
政策和策略
6.1 政策/策略-1 名称或描述
6.2 政策/策略-2 名称或描述
6.3 ...
-
详细系统设计
7.1 模块-1 名称或描述
7.2 模块-2 名称或描述
7.3 ...
-
可追溯性
-
术语表
-
附录
您可以使用这个大纲来描述您的架构并准备 DDS 文档。您做得越清晰、越详细,在实施和测试阶段对开发者和测试者就越有利。接下来,我们将探讨开发阶段。
软件开发
在 SDLC 的这个阶段,软件开发者开始实际开发产品。所使用的技术、编程语言,包括所有技术标准,应与 DDS 文档中同意的内容一致。记住,当设计规范详细且以适当的方式组织时,开发活动可以非常顺利地完成。
测试
我们得到了我们想要的东西吗? 在将产品推向最终用户之前对其进行测试是必须的。这个阶段与开发阶段同时开始,此时开发者负责测试他们正在开发的内容。在这个时候,这只是基本的测试,并不能说产品已经准备好上线。
因此,一旦特定模块或整个功能集的开发活动完成,就应该进行官方测试周期。在此阶段,应进行多种类型的测试,每个功能都应该彻底测试,并且应将识别出的缺陷报告给开发者以修复。
质量保证团队可以使用 SRS 中记录的测试用例,或者他们可以参考用例来测试产品。建议在开发者发布产品新版本时运行测试用例,直到达到稳定版本。这是为了确保在之前的周期中报告的所有缺陷都已关闭。
部署和维护
软件开发者往往将大部分时间投入到产品的设计和开发活动中,这是好的。尽管它很重要,但我从几个项目中了解到这还不够。制定部署和维护的战略计划是产品成功的关键因素。
在这个阶段,重点是使产品对最终用户可用,以便他们可以开始使用它。为此,产品应部署到生产环境。
首先,建议你在测试或预生产环境中部署产品。这就是应该进行用户验收测试(UAT)的地方。所有问题都将在此环境中解决并部署回来。一旦产品达到一个稳定版本,被客户接受,并且满足之前阶段批准的所有规格,产品就可以转移到生产环境。
重要提示:
用户验收测试是最后的测试环节。由客户执行,以验证软件提供的每个功能是否正常工作,并确认所有要求都已涵盖。这将确保软件的行为与用户期望的完全一致,并且他们可以轻松使用而不会出现任何错误或崩溃。在 UAT 结束时,客户应接受软件或在将软件转移到生产环境之前要求一些改进。
维护阶段在产品在生产环境中完全运行并得到客户确认后立即开始。从客户的角度来看,这是一个关键步骤,因为它确保他们的产品在部署后继续按设计运行。
维护类型
软件维护有四种类型:
-
纠错性维护:这主要用于纠正在使用系统时观察到的某些错误和故障,或提高系统的性能。
-
适应性维护:当客户请求在新的环境中运行软件,如新的硬件或新的操作系统时,可能需要这种维护。有时,客户请求将他们的产品从本地环境迁移到Azure 云。此外,它还可以涵盖将产品与第三方软件集成。
-
完善性维护:这种维护类型专注于在产品中实现新功能。这些功能可能是客户为了适应新的业务案例而请求的,或者是由已经开始与产品互动并注意到一些可以帮助他们工作并提高整体体验的缺失功能的使用者报告的。
-
预防性维护:这通常用于检测和纠正可能导致未来软件故障的错误。它有助于降低目前不显著但可能在未来造成严重问题的风险;例如,假设客户预计在两个月后将有更多的用户开始使用他们的产品,但当前的规格无法容纳这种负载。在这种情况下,提前规划和更新软件环境以服务由新用户引起的负载被认为是预防性维护。
让我们查看以下表格,了解何时以及为什么应该应用这些维护类型:

图 1.9:软件维护类型
在下一节中,我们将探讨软件维护与保修之间的区别。
维护与保修的比较
人们可能会对维护和保修感到困惑。软件保修是一种正式的法律保证,即产品将按照规格在一定的期限内正常工作。这是在保修期内免费修复系统中的任何错误或故障的承诺。
维护协议是针对长期和持续维护活动(如升级、更新或产品增强)出售给客户的。
我们刚刚解释了 SDLC 的不同阶段,并强调了每个阶段的预期输出。在下一节中,我们将概述流行的 SDLC 模型。
在本节中,我们探讨了 SDLC 的所有阶段,从规划和需求分析到部署和验收。在下一节中,我们将了解最流行的 SDLC 模型。
熟悉流行的软件开发生命周期(SDLC)模型
每个产品都需要一个合适的方法来开发它。通常,这个决定是基于多个因素,例如需求是否记录良好,需求是否不模糊,项目是否短小,等等。在本节中,我们将突出一些在软件开发中使用的最流行的模型。
瀑布模型
瀑布模型是一种直接且顺序化的软件开发方法。在进入下一个阶段之前,应该完成开发周期的每个阶段,并且通常,每个阶段的输出被认为是下一个阶段的输入。
下面是这个模型不同阶段的表示:

图 1.10:瀑布阶段
瀑布模型的一些优点如下:
-
阶段定义明确且易于理解
-
阶段有良好的文档记录
-
对于需求定义明确的较小项目,效果良好
该模型的一些缺点如下:
-
产品的工作版本将在开发周期的后期阶段交付。
-
对于复杂和持续的项目来说,这不是一个好的模型,因为利益相关者无法在开发过程的早期阶段提供反馈。
-
当需求变更风险较高时,这不是一个好的模型。
敏捷模型
敏捷模型,例如 Scrum,是最知名的开发方法之一,被许多 IT 组织广泛采用。它也应用于非技术项目。
此模型的方法是将产品分解成周期或迭代。每个迭代大约持续 2-4 周(通常,时间不应过长)。在每个迭代中,开发团队应交付一个完整的软件工作版本。想法是将用例分解成迭代,以便在迭代结束时得到产品的一个功能部分。这样,开发团队就可以产生持续的和增量发布,这些发布已经过良好的测试。
这种方法有助于团队早期识别和解决问题。它还涉及利益相关者在整个开发过程中,以获取他们的反馈。
以下图表是敏捷阶段的快速表示:

图 1.11:敏捷阶段
螺旋模型
螺旋模型 是迭代模型和瀑布顺序模型的结合。通常用于大型项目,它为每个迭代的早期阶段的风险处理提供支持。使用此模型,项目通过以下四个阶段:
-
通过收集业务需求来识别目标
-
进行风险评估
-
审查和评估
-
开发和测试
下面是描述螺旋模型的图表:

图 1.12:螺旋模型
在每个迭代中,你可以构建新功能和新功能的原型,这些功能将在本次迭代中交付。
这些阶段以 螺旋 形式重复,直到整个产品交付,允许进行多轮细化。
螺旋模型的优势如下:
-
此模型提供了风险存在的早期迹象。
-
首先开发关键高风险功能。
-
利益相关者与整个开发生命周期阶段紧密相连。
-
用户可以通过使用原型在早期阶段看到系统运行情况。
-
利益相关者可以尽早并持续地提供反馈。
螺旋模型的缺点如下:
-
此模型成本高昂,不推荐用于大多数情况下风险较低的小型项目。
-
管理过程相对复杂。
-
运行此模型需要风险评估的专业知识。
DevOps 模型
在 DevOps 模型 中,开发人员和运维团队共同工作。你可能想知道,这究竟意味着什么?
使用我们之前讨论的传统模型,公司会将资源分割成处理特定责任的团队:
-
开发团队来架构和构建产品。
-
一个操作团队来准备环境和托管产品。
-
一个测试团队来准备测试用例,进行彻底的 QA 测试,并向开发团队汇报。
使用 DevOps 方法,开发团队和操作团队被要求在整个 SDLC 流程的各个阶段紧密合作——作为一个团队。一个成功的 DevOps 模型确保了持续的反馈,加速了部署,改善了开发过程,并自动化了手动流程。
这里展示的是 DevOps 模型中不同步骤的表示:

图 1.13:DevOps 模型
DevOps 模型的优势如下:
-
特性快速交付
-
更好地响应问题
-
高效的运营
-
减少瓶颈
-
更好的沟通和协作
-
更高效的团队成员,有更多时间进行创新
DevOps 模型的缺点如下:
-
DevOps 需要文化变革和新的沟通方式,这在传统环境中是一个巨大的挑战。
-
需要升级基础设施以优化流程,这对某些公司来说可能是昂贵的。
-
快速开发可能导致关键的安全漏洞。
现在,让我们学习如何选择正确的模型。
选择正确的模型
当选择合适的 SDLC 模型来构建特定产品时,重要的是要记住,每个模型都提供了一种独特的过程,这可能有助于你在开发周期中克服遇到的挑战。没有一个模型适合每个项目或每个客户的需求,这就是为什么你应该了解这些流行的模型,并知道何时应用它们。
选择正确的模型很大程度上取决于项目执行的因素,例如你当前的基础设施、你团队采用的文化以及客户希望如何管理项目。某些项目可能最好采用瀑布方法,而其他项目则可能从敏捷模型的灵活性中受益。
让我们看一下以下表格,它突出了选择产品正确模型时的主要因素:

图 1.14:如何选择正确的 SDLC 模型
在本节中,你探索了最流行的 SDLC 模型。每个模型都提供了一种独特的方法,可以帮助你克服你在职业生涯中可能遇到的不同挑战。你还学习了如何为你的产品选择正确的模型。
摘要
在本章中,你学习了软件开发生命周期(SDLC)的定义及其重要性,以及它如何帮助组织以高效的方式交付产品。然后,你了解了 SDLC 的不同阶段、最流行的模型,以及它们的优缺点,以及如何为你的团队选择合适的模型。
在下一章中,你将学习不同的团队角色,以及它们的职责,以及它们如何融入 SDLC 流程和团队结构。
第二章:第二章:团队角色和职责
在上一章中,我们涵盖了软件开发生命周期的所有基本阶段。现在,让我们了解不同团队角色如何参与这些不同阶段的执行。
员工是组织最重要的资产之一。一个成功的软件项目的关键因素之一是确保开发团队的关键成员都到位。项目的成功也取决于团队如何协作以及沟通效率如何,以便提供最佳结果。本章重点关注典型软件开发团队中的主要角色及其相应的职责。
本章将涵盖以下内容:
-
探索开发团队层级
-
突出组建团队时需要考虑的五个关键属性
在本章结束时,你将了解软件开发团队中的典型层级结构以及每个成员应承担的职责。
探索开发团队层级
在许多情况下,客户会好奇为什么我们要分配不同的角色和专长来构建产品。确实,他们期望一个软件工程师的角色就足够了。本章旨在解答这一疑问,并强调每个成员在敏捷开发团队中扮演的特定角色,以便提供最佳性能。
通常,当你开始组建软件开发团队时,选择角色以及每个成员的责任取决于对以下两个问题的回答:
-
你将开发什么类型的产品?
-
将采用哪种工作方法?
以下图表显示了敏捷软件开发团队的关键职位。你会注意到我们突出显示了解决方案架构师职位;他们在技术和非技术团队之间扮演联络角色。这个人将设计解决方案的架构:

图 2.1:开发团队层级
让我们更深入地探讨团队中的每个角色及其职责。
项目经理——项目的教父
项目经理(PM)是一个有组织、注重细节且对项目估算技术有良好了解的人。项目经理负责了解项目的关键利益相关者,并有效地与他们沟通,以规划、安排时间表、准备预算、执行任务,并确保软件产品的交付和完成。
项目经理(PM)的职责和责任可能包括以下内容:
-
从需求分析到测试和维护的整个项目阶段规划
-
与客户协调确定项目将采用的方法
-
分配所有成功完成项目所需的资源,并确保他们拥有适当的软件工具和硬件环境以实施和测试项目
-
提出项目时间表并安排每个阶段的任务
-
通过分配任务给团队成员并确保他们按时完成,领导并监督项目每个阶段的成功执行
-
激励团队成员提供高质量的输出
-
制定项目预算并向高级管理层提供定期状态报告
-
确保团队成员充分理解需求,制定和传达变更请求,并确保输出与客户期望的一致性
接下来,根据团队层级,我们将检查功能分析师的角色。
功能分析师——探险家
功能分析师负责确保所有需求都与客户进行了彻底的讨论和分析。完成此操作后,需求将被捕获、正确记录并在任何开发活动开始之前清楚地传达给团队。
他们无论业务流程多么复杂,都发挥着将业务流程转化为技术团队能够开发的逻辑和功能需求的重要作用。他们的角色是弥合商业用户及其期望与开发团队之间的差距,开发团队负责构建产品。
这个角色可能有不同的名称,如需求分析师、系统分析师或商业分析师,但它们都或多或少地处理相同的职责。
功能分析师的一些职责包括以下内容:
-
与客户利益相关者、管理团队和商业用户会面,并收集需求
-
确定要构建的产品的主要目标
-
分析技术和商业需求并记录它们
-
确保需求得到适当的沟通和解释,以便开发团队
-
测试最终产品以验证目标并确保结果符合客户的商业目标和用户的需求
接下来,我们将探讨解决方案架构师的责任。
解决方案架构师——变革者
解决方案架构师负责领导技术设计和管理针对特定商业需求的解决方案的整体工程方面。
该团队成员应具备平衡的技术和商业技能组合,以便创建解决方案架构。
解决方案架构可能是一个多阶段过程,涉及一系列针对特定受众和商业目标的问题。因此,主要重点是分析和理解业务模型的所有部分,包括在早期阶段定义的所有需求。
然后,他们需要设计一个特定的解决方案,并介绍解决方案的整体技术愿景,该愿景应适合当前环境以及客户的期望。解决方案架构将传达给整个开发团队,然后他们将在设计规范和要求的基础上实施解决方案。
解决方案架构师的一些职责包括以下内容:
-
分析和理解需求,然后提出解决方案的架构设计
-
评估当前的技术和系统,以在要构建的产品和现有系统之间引入集成链接,以满足客户的需求
-
对所有利益相关者保持透明,并告知他们关于当前实施产品中存在的任何技术问题,然后提出解决方案
-
在评估其对最终产品可能产生的影响后做出技术决策
-
记录提出的解决方案,并监控所有请求的更新,以确保它们不会对解决方案的整体设计产生影响
-
推荐适合产品正常运行的正确硬件,并与 IT 专业人员协调,准备必要的环境以构建、测试和托管产品
-
应对常见的项目挑战,例如团队技能、沟通冲突、不明确的需求和不切实际的截止日期
-
提前识别可能的风险,以防止在实施过程中出现任何意外
-
与项目经理和团队领导协调,准备项目时间表和详细进度安排,这将作为估算所需工作的主要输入
-
协调开发人员和团队领导,以解决出现的技术问题
-
通过定期研究现有技术并向开发团队提出改进流程的更改和新技术来指导开发团队
此角色需要深入了解以下领域的专业技术知识和实践经验:
-
业务分析,通过将业务流程转化为功能用例来帮助理解和改进业务流程
-
IT 基础设施,推荐适合产品的正确环境
-
软件架构设计,为产品提出现代解决方案架构
-
云开发,开发和部署解决方案到云,以及在转向云时简化SDLC
-
DevOps以帮助改进敏捷开发生命周期
接下来,我们将了解开发主管的职责。
开发主管——技术达人
开发主管负责领导和支持开发人员实施产品的所有技术方面。然而,在开始开发之前,他们将与团队紧密合作,为所需工作提供准确的估计。项目经理将使用此评估来创建项目时间表,并为所有任务提供结构化的分解。
技术负责人应与项目经理有效沟通,提供开发活动的定期进度报告。另一方面,技术负责人还应与解决方案架构师沟通,以便及时以专业的方式解决技术问题、变更或冲突。
技术负责人的主要职责之一是确保与团队成员执行编码标准和最佳实践,并确保它们清晰且易于应用,以便开发的代码在任何时候都可以重用、可读和可扩展。
开发领导的一些职责包括以下内容:
-
管理日常任务和组织团队活动
-
举办技术培训课程,指导团队成员学习新技术和技巧,并确保他们应用统一的标准
-
评估团队绩效并提出改进和目标
-
持续倾听团队成员的反馈和关注点,以解决可能影响团队士气或工作进度的问题或冲突
-
激励团队成员提高他们的分析思维和创造力
-
提议和组织团队建设活动
-
发展团队优势,改进弱点
-
认可团队成就并与管理层协调以奖励成就
接下来,我们将探讨软件开发人员的职业道路。
软件开发人员——魔法大师
软件开发人员负责正确理解项目早期阶段定义的需求。然后,他们根据与项目经理和客户商定的进度表开始开发模块和功能。任何无法由团队领导澄清的需求模糊性应与功能分析师或解决方案架构师讨论。这对于降低项目风险和确保高质量的可交付成果至关重要,这将导致项目的成功。
软件开发人员有三条职业道路可以选择:
-
前端开发:在这种情况下,他们负责交付产品客户端块。通常,他们使用前端编程语言,如HTML和JavaScript。他们应熟练掌握jQuery、CSS(SASS或LESS)以及响应式框架,如 Bootstrap。在现代网络开发中,由于存在 JavaScript 框架,如 Angular、React 和 Vue,前端开发者非常受欢迎,这些框架用于构建单页网络应用程序:
a. Angular:这是一个由 Google 的 Angular 团队开发的开源 JavaScript 框架。
b. React:这是一个由 Facebook 的 React 团队开发的开源 JavaScript 框架。
c. Vue:这是一个由前 Google 的AngularJS框架开发者 Evan You 创建的开源 MVVM JavaScript 框架。
-
后端:在这种情况下,他们负责开发产品的服务器端功能块,如 Web 服务或 Web API。他们还负责设计和创建数据库,包括所有 SQL 查询和事务。每个后端开发人员应具备的一些主要编程语言和技能包括以下内容:
a. .NET C# (.NET Framework 和 .NET Core)
b. ASP.NET MVC 和 Web API
c. N 层架构
d. Entity Framework 和 ADO.NET
e. MSSQL 数据库和查询
f. Azure Blob 存储空间、Azure 应用服务以及 Azure Functions
g. 微软 Power Automate
h. 在 Azure 上部署 Docker 容器
i. HTML、JavaScript 和 jQuery 的知识
j. 一个 JS 框架,如 React、Angular 或 Vue
k. 单元测试
l. 团队基础服务器或 Git 用于源代码控制和版本管理
m. Azure DevOps 用于管理源代码或开发周期
-
全栈:这个角色是前两个轨道的组合。
软件开发人员的一些职责和责任包括以下内容:
-
根据需求、规范和编码标准研究、设计和实现干净高效的代码
-
与团队领导协调任务和日常日程
-
修复报告的问题,并具有提出解决方案的能力
-
在测试环境和生产环境中部署和测试产品
-
提供专业的代码文档,并支持用户指南文档的准备
-
为提高质量和整体性能,参与代码审查会议。
-
根据需要,向团队领导提供每日或每周的状态报告。
-
与团队领导协调解决任何需要高级专业知识才能解决的问题。
接下来,我们将学习 QA 工程师的责任。
质量保证——质量守护者
QA 工程师或软件测试员负责对产品进行全周期测试,以确保所有需求和用例都已开发,并且产品无缺陷。为了实现这一目标,他们应从需求或用例中创建测试用例。目标是测试产品中的每个单个功能或流程,然后与开发人员协调,提供重现缺陷的步骤。一旦开发人员修复了缺陷,QA 团队应进行另一轮测试以确认修复。
QA 工程师的一些职责包括以下内容:
-
与 IT 专业人员协调,确保在开始产品测试之前测试环境已准备就绪
-
创建测试用例并运行测试计划以测试产品的所有功能
-
识别缺陷并记录所有步骤和细节,以帮助开发人员解决这些缺陷
-
监控性能和生成指标,这将有助于提高产品的效率
-
进行安全测试以识别安全威胁和预防漏洞
到目前为止,我们已经讨论了典型敏捷团队的各个角色及其专业特长。在下一节中,我们将强调在组建团队构建你的产品时需要考虑的某些个性特征和额外事项。
强调在组建团队时需要考虑的五个关键属性
建立一个有效且目标明确的团队,具有明确的目标可能会具有挑战性,因为它汇集了不同的文化、态度和沟通技巧。如果你与负责管理团队的资深经理交谈,他们会告诉你,他们面临的最重大问题是与团队为完成所需工作所采用的沟通问题和内部流程相关。这就是为什么在你的流程中拥有一种协议、团队规范、标准或最佳实践,以帮助团队相处并建立有效的人际关系以实现目标很重要的原因。
在以下子节中,我们将逐步介绍在组建软件开发团队时需要考虑的一些关键属性。
建立优秀的团队文化
根据技术资格招聘团队成员很重要。然而,你不想招聘一个没有和谐且不能作为一个整体进行沟通的团队,以正确实现你的目标。
通过选择具有化学反应、能够协作、拥有共同愿景并能有效协作的成员来建立一个强大的团队。在评估候选人时,考虑以下个人特质以支持公司文化:
-
具有积极态度
-
是一个团队玩家
-
具有自我激励
-
具有强烈的职业道德
-
注重细节
-
是一名优秀的沟通者
-
是一个自我提升者
-
具有适应性
-
是一个诚实的人
建立开发标准和最佳实践
制定规则和标准可以带来良好的结果和更好的代码可维护性。有许多常见的标准你可以应用。然而,保持标准与团队中每个人的相关性、简单性和清晰性很重要。
关于最佳实践,它们是一套已经显示出良好结果或改进过程的方法或技术。因此,建议您分析现有的流程,并根据以往的经验提出最佳实践。
为团队配备正确的工具
他们说“你只能像你使用的工具一样好”,因此,为你的团队提供能够帮助提高团队协作并允许团队更有效地完成任务的工具至关重要,这将减少人员流动。
这里有一份必须拥有和推荐的工具列表,这些工具将支持你构建你的.NET 产品:
-
Visual Studio 和 Visual Studio Code:这是.NET 解决方案的主要开发 IDE。
-
Azure DevOps:这是由Microsoft提供的一个在线平台,提供 DevOps 工具以开发、测试和部署软件产品。
-
Azure Storage Explorer:这是 Microsoft 提供的一款免费工具,允许用户轻松浏览和管理多个 Azure 云存储账户。
-
Service Bus Explorer:这是一个允许用户轻松连接到 Service Bus 命名空间并执行管理和数据操作的工具。
-
Notepad++:这是一款免费工具,用作文本和源代码编辑器。它支持多种语言,是常规记事本的绝佳替代品。
-
Postman:这是一个用于 API 测试的协作工具。
-
Snagit:这是一款截图和视频捕获工具(如果您负担不起 Snagit 的许可证,可以使用Windows Snipping Tool)。
-
GitHub Desktop:这是一个简化您开发流程的开源工具。
-
PowerShell:这是 Microsoft 的一个命令行外壳,通过在PowerShell中编写脚本并使用 Windows 任务计划程序安排执行触发器来自动化任务。
-
Fiddler:这是一个用于检查开发服务器和 Web 服务器之间 HTTP 和 HTTPS 请求的调试工具。
-
NuGet Package Explorer:这是一个具有易于使用的 GUI 的开源工具,允许您创建和探索NuGet包。
-
Regex101:这是一个允许您生成和测试正则表达式语法的工具。
-
JSFiddle:这是一个在线 IDE 工具,您可以使用它来测试和展示 HTML、CSS 和 JavaScript 代码片段。
-
U2U CAML Query Builder:此工具允许您轻松构建SharePoint CAML查询。
接下来,让我们学习如何有效地提高团队内部的沟通。
保持持续沟通
关于成功团队运营的一个关键因素是有效的沟通。以下是一些提高团队沟通的建议:
-
鼓励双向反馈并练习积极倾听。
-
团队成员应清楚自己的角色和预期责任。
-
通过引入团队活动来培养团队精神。
-
利用云工具进行协作,并减少可能造成分心的后续会议数量。这将使您能够明智地利用时间。
-
提供培训课程,帮助培养必要的沟通技能。
-
鼓励接受建设性批评。
-
持续评估团队沟通并提出改进建议。
帮助开发者专业成长
员工保留非常重要;公司应采取主动措施提高员工满意度,并让他们致力于交付高质量的工作以及推动更多生产力。
追求这一目标的一种方式是为每个团队成员根据其角色和责任制定专业成长计划。
这里有一些有助于团队成员专业成长的建议:
-
确定每位团队成员所需的软技能,并提出他们可以采取的行动来提高。
-
总是给予认可和奖励。
-
定期评估团队成员,而不仅仅是年度审查期间。
-
为每位团队成员设定目标和制定培训计划。
在本节中,我们强调了可能影响您团队有效性的关键属性。
摘要
作为解决方案架构师,您的角色是构建和领导一个团队以交付成功的项目;如果您没有良好的团队建设技能,这是无法实现的。本章旨在帮助您团结一个成功的开发团队,该团队由在 SDLC 过程中参与的不同角色组成。
在本章中,您了解了典型软件开发团队中确定的不同角色、他们的职责以及他们如何相互协作以完成任务。接下来,我们强调了在组建团队时需要考虑的一些关键属性,例如团队文化、应用标准和最佳实践、强大的团队沟通以及专业团队成长。
在下一章中,您将快速了解解决方案架构实际上是什么。然后,您将了解解决方案架构师的角色及其相关职责。之后,我们将强调一些关键个性特征,这些特征将支持您成为一名有效的解决方案架构师。
第三章:第三章:什么使解决方案架构师有效?
在上一章中,我们强调了软件开发团队中不同角色的重要性。我们还探讨了支持你组建强大且成功的团队的关键属性。为什么你需要学习这些? 因为你可能雇佣了最好的候选人,但如果你没有建立适当的文化,如果团队成员不能有效地相互沟通,你可能会失去项目或客户。
在本章中,我们将主要关注解决方案架构师的角色。此外,我们还将详细阐述一系列个性特征,这些特征应该能够帮助你有效地领导当今的数字世界。
在本章中,我们将涵盖以下主题:
-
解决方案架构概述
-
探索每个解决方案架构师都应该具备的基本软技能
-
了解应避免的一些常见陷阱
-
学习企业架构师、技术架构师和解决方案架构师之间的区别
到本章结束时,你将了解什么是解决方案架构。此外,你将了解作为解决方案架构师,你应该具备的核心个性特征,以增强你的架构思维和领导技能。
这些个性特征对于成功至关重要,因为解决方案架构师的角色必须处理许多非技术方面,例如团队建设、与客户谈判、解决冲突、改进业务流程,以及在团队内部营造创新和专业文化的氛围。
什么是解决方案架构?
在我们深入探讨解决方案架构师的个性特征之前,首先,让我们了解一下什么是解决方案架构。解决方案架构是一系列旨在根据预定义的需求探索和分析业务问题,并为拟议的技术解决方案创建一个与客户目标和需求相匹配的架构设计的活动。
通常,在创建平衡且有效的解决方案及其架构设计时,解决方案架构师应考虑以下四个关键因素及其相关限制:
-
企业限制:识别构建产品背后的企业限制和目标。
-
利益相关者的视角:理解和分析从业务利益相关者和高级用户收集到的需求。
-
技术价值:识别你的解决方案中使用的科技栈和组件的价值,这些应该符合企业战略指南和最佳实践。
-
项目限制:解决方案架构师应考虑项目的时间表和预算。
下面是一个总结你在解决方案设计中应考虑的不同限制的示意图:

图 3.1:理想的解决方案应考虑这些约束
到目前为止,这似乎很简单,对吧?解决方案架构是设计和管理整个解决方案工程的过程,它通过执行一系列实践来解决业务问题。这应该在开始任何开发活动之前由解决方案架构师完成,我们将在本书的后面部分更详细地探讨这一点。
现在,让我们深入了解一个解决方案架构师应该具备的一些基本个性特征。
探索有效架构师的个性特征和技能
在今天这个快速变化和颠覆性的商业世界中,成为一名有效的解决方案架构师既是挑战性的,也是变革性的。
在本节中,我们将探讨一些最重要的个性特征、软技能和品质,这些品质是成为一位高效、实用且以业务价值为导向的解决方案架构师所必需的,他可以在公司内部产生影响。
以身作则
解决方案架构师负责领导一个解决方案或产品的所有架构活动。他们应该为团队设定正确的方向,推行创新文化,并构建鼓舞人心的愿景。作为解决方案架构师,你应该证明的领导技能之一就是以身作则——言行一致。那么,这究竟意味着什么呢?让我们设想以下情况:
-
有一些领导者要求人们加班解决问题,但自己却准时下班。
-
有一些管理者要求你减少在改善硬件或招聘新团队成员上的支出,但自己却购买了豪华的办公家具。
-
有一个管理者要求他的团队明智地使用时间以提高生产力,但后来被发现他在工作时间花费大量时间在社交媒体上。
你听说过这类领导者吗?
对于伟大的领导者来说,行动比言语更有说服力。没有比看到一位无能的领导者说一套做一套更能迅速扼杀团队热情和动力的了。这可能会非常令人失望,并导致士气低落,这对团队来说可能是毁灭性的。
作为解决方案架构师,你必须知道你对你的团队负有责任。他们密切地关注你的一举一动,因为他们正在寻找指导。你必须激励他们,推动他们取得最佳成果。做到这一点的方法就是做一个好榜样。你的行为必须与你所说的一致。
这里有一些你可以用来以身作则并赢得团队信任的方法:
-
在困难时期,要亲力亲为,承担责任,支持你的团队。不要只是袖手旁观,告诉他们该做什么。
-
总是应用你设定的规则和标准,以便你的团队能够跟随你。
-
同理心是必不可少的;对团队成员的情感要有敏感度。
-
花时间让每个人在团队和整个组织中感到特别和重要。
-
以你希望被对待的方式对待你的团队成员。
-
并非所有团队成员都相似;挑战自己更好地了解他们,接受他们本来的样子,并尊重他们的独特差异。
-
倾听批评,因为有时它可能是建设性的。在这样做的时候,避免表现出防御性。
-
工作场所的人际冲突可能会发生;你无法避免它们。然而,确保你尽快解决它们。
-
永远不要把人当作理所当然。
当你言行一致时,你通过向团队成员展示如何正确做事来领导他们,也就是说,你为他们树立了良好的榜样。这样,你成为一个更有效的领导者。
展示出色的沟通技巧
解决方案架构师的关键能力之一是拥有良好的沟通技巧,这对于建立关系至关重要。记住,你的角色要求你与客户协商并解决与团队成员之间的任何冲突。你必须是一个好的倾听者,不仅是为了回应,也是为了正确理解各方的需求。沟通技巧的缺乏可能造成严重的瓶颈。然而,相反,能够有效地沟通是项目成功的关键因素,因此也是解决方案架构师成功的关键因素。
这里有一些你可以用在日常与团队成员互动中的小贴士,以实现有效的沟通:
-
表现出同理心,因为它创造了相互理解和信任。
-
在困难的讨论中给予团队成员赞美,例如说“我认为你所说的很棒”,“我同意你的观点”和“你到目前为止做得很好”,这将提高他们的动力并提升团队的士气。
-
并非所有人都会和你有相同的观点;愿意尊重他人的观点,不要无礼或傲慢。
-
眼神交流很重要,因为它可以提高沟通质量,大多数人认为它是值得信赖的标志。在交谈时尽量看着对方的眼睛。
-
尊重每个人发言的机会,并尽力不要打断。
除了这些建议之外,尝试在如何管理与团队成员或客户的特定对话方面有一个清晰的方向。尽量保持直接;否则,它可能变成一场无用的争论。
下面的图表显示了你可以实施的四个步骤,以实现有效和高效的讨论:

图 3.2:实现高效会议的步骤
为什么沟通在工作场所很重要? 让我们来看看:
-
清晰的沟通通过向团队描述你的目标来展示你的领导能力。此外,它使你的工作场所更具协作性和敏捷性。
-
有效的沟通对团队的效率有重大影响,因为它使他们参与重要的技术或非技术决策。
-
它营造了一个积极的工作环境,并改善了与客户和同事的关系。
-
它提高了团队的效率,因此增加了组织的利润。
沟通技巧对于向你的团队和客户传达你的想法和愿景至关重要。记住,最大的沟通技巧是倾听他人,因为这将帮助你理解情况并做出适当的决策。
拥有深厚的分析技能
“分析”这个词已经成为每个高级技术职位的热门词汇。那么,分析技能是什么,为什么它们对你作为解决方案架构师来说是必不可少的呢?
分析技能指的是你如何调查特定问题或业务流程,通过理解不同元素是如何相互关联的,逻辑和深思熟虑地收集和分析所有相关信息,研究可能的解决方案,然后为该情况提出理想的解决方案。
设计解决方案受多种因素影响;它需要一个注重细节、具备深厚分析技能并能评估各个方面、处理需要分析的任务的个人。
这些是你需要找到解决各种问题和困难或帮助你的团队成员通过提出适当的解决方案来解决他们面临的问题的技能。
你可以通过走出你的舒适区并开始解决复杂问题来发展你的分析技能。以下是一些解决方案架构师应该掌握的核心分析技能:
-
数据分析:你必须有能力分析接收到的数据,并识别出支持你决策的模式和趋势。
-
沟通:你必须是一个好的沟通者,以便向你的团队解释你的发现,这样客户就可以描述你的建议。
-
批判性思维:你必须有能力分析复杂问题并评估你收集到的信息,以形成合理的决策。
-
创造力:你应该有能力超越显而易见的解决方案,以找到最佳解决方案。
-
研究:你必须更多地了解你试图解决的问题。你可以通过研究相关的在线文章和帖子,了解其他架构师或竞争对手是如何解决特定问题的,这可能会支持你在头脑风暴可能的解决方案。
作为解决方案架构师,你应该具备扎实的分析技能,因为它们将帮助你解决在设计或开发解决方案过程中可能出现的复杂问题。
展示出色的项目和资源管理技能
解决方案架构师不直接对这些两个方面负责。然而,他们被期望关注业务成果。因此,他们负责以最有效的方式完成项目,确保以下方面:
-
客户的商业目标正在实现。
-
项目正在给定的时间框架和预算内实施。
-
团队技能和资产得到了适当的分配,并且正在被高效地用于完成项目。
你被期望介入五个主要的项目管理活动:
-
项目启动:这是在明确项目目标和范围之后。
-
需求收集和规划:这包括制定工作分解结构。
-
项目执行:这是基于产生的进度表。
-
性能监控:这也包括管理变更请求。
-
项目收尾。
这里有一个图形表示这些主要的项目管理活动:

图 3.3:项目管理的五大活动
解决方案架构师在资源管理中扮演着重要的角色,这是项目管理的一个关键部分。它是规划并高效分配资源的过程,以确保在项目最早阶段定义的估计时间内、预算和范围内完成项目。在软件开发中,有两种类型的资源和资产:
-
无形资产 包括各种非物理资产,例如员工技能、经验、公司声誉和时间。
-
有形资产是物理资产,例如设备、材料和投资。
拥有项目和资源管理技能对于在整个开发过程中提供战略方向至关重要,无论是做出技术决策还是非技术决策。
对他人展现耐心
耐心 是人类的一种力量。它被认为是一项难以掌握的技能;然而,如果你想成为一名有效的解决方案架构师,你必须有耐心,尤其是在危机期间。对工作中的他人保持耐心是面对困难时保持平静并积极回应同事和客户的能力。
在我们快速变化的世界里,期望任务能够即时完成,延误可能会造成压力。例如,你的客户会希望他们的项目按时交付,或者你的经理会期待你分配给你的团队中某人的报告,而这个人没有按时交付。想想那些不断改变要求的客户,想想那些可能有坏习惯、难以相处或难以理解的同事。所有这些困难的情况都超出了你的控制范围,它们可能会让你瞬间感到沮丧。
对这些人失去耐心可能会使情况复杂化。这可能会损害你的关系,并给你留下不好的印象。
协作工作
构建架构设计和交付解决方案是一个团队的努力。一个有效的架构师可以与所有同事(包括那些具有不同技能和专业知识的人)协作,目标只有一个,那就是高效地交付项目并满足客户的目标。
让我们看看以下为什么协作很重要的原因:
-
它帮助你和团队更快地解决问题。
-
它提高了动力,使人们更加团结,这可以提高留存率。
-
它创造了一个学习和发展的环境,因此团队成员可以从彼此那里学习。
-
通过消除限制、促进部门间的透明度以及让团队成员参与项目中的大多数决策,它创造了一个更顺畅的工作环境。
-
它创造了一个充满创造力和创新的工作环境,所有成员都可以分享他们的想法以进行创新。
作为解决方案架构师,协作工作对于你的角色至关重要。这是因为当你与团队协作时,你不仅确保了良好的架构交付,而且在开发结束时还确保了高质量产品的交付。
展示影响力和谈判技巧
强大的影响力和谈判技巧对于解决方案架构师解决冲突和发展双赢解决方案至关重要。谈判是与客户或团队成员讨论问题并达成双方都满意协议的能力。影响是成功谈判的关键部分。它是谈判并说服他人接受你建议的能力。
这里有一些基本的谈判技巧,将支持你成为一个有效的谈判者:
-
将谈判流程与你的短期和长期战略目标保持一致。
-
在开始谈判之前,尝试通过收集关于你要见的人和你要谈判的主题的信息来彻底准备。
-
准备你的谈判协议的最佳替代方案(BATNA)。以防在当前的谈判中未能达成协议。
-
能够通过区分个人问题和谈判问题来保持理性。这对于看到机会和实现谈判目标非常重要。
-
了解如何通过与具有共同利益并能够影响谈判中其他人的潜在盟友讨论你的想法来建立联盟。
-
与你谈判的人建立信任和声誉。你可以通过尊重、透明和信守承诺来实现这一点。
你将始终处于需要影响你正在设计的解决方案中涉及决策同伴的情况。继续发展你的谈判技巧,建立稳固的关系,解决冲突,达成伟大的交易。
拥有广泛的技术专长
要成为真正的创新支柱,解决方案架构师应具备广泛的技术专长,能够就技术建议咨询管理层和工程团队。特别是,他们需要意识到以下几点:
-
软件工程和架构设计
-
信息技术架构、基础设施和云计算开发
-
项目管理和产品管理
-
DevOps 工具和实践
-
业务分析
高效地分解问题
大问题难以处理;有时,它会使你感到不知所措。以积极的态度面对问题,通过将其分解为比原始大问题更容易解决的较小问题,让自己和团队更容易应对。
优秀的架构师还可以最大限度地减少问题的发生,并在它们发生之前解决它们。这可以通过进行良好的风险评估和关注细节来实现。
实事求是
每个组织都有自己的标准、内部政治、截止日期、预算等等。优秀的架构师应该意识到在项目实施过程中可能遇到的限制。因此,他们应该以实际的方式处理问题,而不是使用不适用于所有情况的理论。他们应该提出现实、及时、务实和高效的解决方案,以适应这些限制。这就是基于业务价值进行架构决策的地方,以优化公司的投资回报率(ROI)。
到目前为止,我们已经讨论了一些解决方案架构师的基本性格特征和关键技能。在下一节中,我们将突出一些常见的错误,您应该注意避免以防止客户不满和可能影响您项目交付成果的任何关键问题。
查看架构师常见的陷阱
太常出现的情况是,错误是通过艰难的方式学到的。在本节中,我们将突出一些可能影响解决方案架构师成果的陷阱:
-
避免过度架构解决方案;例如,通过向解决方案中添加不必要的层和组件,这些组件可以用简单的类代替。过度架构会增加开发活动,并在出现错误时使故障排除复杂化,这将降低客户所寻求的成果。尽量简化您的架构,使其更符合业务需求。
-
考虑编写自定义代码而不是使用现成的和开源的框架或库。例如,假设你需要构建一个响应式网络解决方案;这里,你有两个选择。
第一个选择是重新发明轮子,自己开发一个响应式框架。这个选项成本较高,因为你需要从头开始开发整个CSS和JavaScript。第二个选择是使用流行的开源框架,如Bootstrap,来构建响应式用户界面,这是一个成本较低的选择。
你应该选择哪个选项? 当然,在这种情况下,最好的选择是使用可靠的开源框架来缩短开发时间,避免如果你开发自己的框架可能会遇到的问题,并利用开源框架提供的强大功能。你需要通过决定哪个选项对你的解决方案是最好的来决定何时编写自己的代码,何时使用开源框架。
-
在规划或设计之前就跳入开发,将使项目的截止日期、预算和目标面临风险。在开始开发之前有一个适当的计划和设计是必须的。它结构化了团队成员的工作,并设定了应与需求相一致的目标。无论你正在处理的项目大小如何,你都应该始终遵循 SDLC 阶段,并采用每个阶段的输出,以便过渡到下一个阶段,直到交付产品。
-
如果不将代码结构化以使其可重用和可扩展,你将在软件的许多位置拥有大量重复的代码,这些代码执行相同的任务。这将增加源代码的大小,并使维护任务复杂化。这是因为代码将变得难以阅读,你可能需要在许多地方修复相同的缺陷。尽量保持你的代码DRY(不要重复自己),创建组件,使你的软件模块化,并在需要时通过创建抽象类和接口应用面向对象编程(OOP)。
-
在不关注安全性的情况下开发产品,将导致一个容易受到安全漏洞攻击的软件解决方案。安全攻击可能会损害系统和其关联的数据库,这可能导致停机,你的客户可能会损失金钱。确保你的软件解决方案不再是一个事后考虑,而是一个首要考虑。在设计和发展软件时关注安全性可以帮助你避免恶意软件并防止黑客攻击。
-
避免依赖传统的开发方法来构建软件,而不是应用敏捷软件开发方法。敏捷方法被软件开发公司广泛使用,以便他们可以有效地管理项目。这是一种现代实践,为你的团队和正在开发的解决方案增加了价值。
敏捷是一种进化过程,通过将来自不同部门的团队成员聚集在一起以交付项目,促进了团队成员之间的高度协作。它提高了团队的生产力,允许在短时间内交付多个成果。此外,它还允许客户通过提供反馈来密切参与每个阶段,从而防止项目结束时出现任何失望。
-
避免不重视代码优化和性能。
-
避免在用户验收测试(UAT)上投入不足的时间。所有类型的测试都非常重要,以便交付高质量的产品。UAT 是一种由客户执行的测试,用于决定是否满足需求。这是在进入生产/实时环境之前。
如果没有适当的 UAT 阶段,产品可能会因为许多原因被最终用户拒绝,例如性能不佳、缺少功能以及产品存在缺陷。为了避免这种情况,确保你提前根据与客户达成一致的使用案例准备测试用例。这些测试用例将在 UAT 阶段用于验证每个功能。
-
避免不分配与项目需求相匹配的正确技能集的团队成员。记住,没有合适的团队成员,成功是不可能的。
-
避免由于不切实际的进度表和预算以及项目后期才发现这些问题而导致良好的规划失败。这可能会产生冲突,特别是如果你正在同时处理多个项目。你必须有一个现实的计划,有明确的截止日期和目标;这应该在项目的规划阶段确定。你可以应用敏捷方法来避免这个陷阱。
这些各种陷阱可能会经常发生,可能还会相互关联,这可能会影响你交付成果的质量以及你在客户那里赢得的声誉。我们已经描述了你可能会遇到的一些许多陷阱中的几个。了解这些陷阱将使你做好准备,以便克服它们。作为一名解决方案架构师,你需要不断解决问题,尝试新事物,并帮助将项目与公司愿景和价值观对齐。
在下一节中,我们将探讨企业架构师、技术架构师和解决方案架构师之间的区别。
企业架构师与技术架构师与解决方案架构师之间的比较
在信息技术行业中,有三个不同的与架构相关的角色。这些角色在软件开发生命周期中同等重要,不能被任何其他职位所取代:
-
企业架构师
-
技术架构师
-
解决方案架构师
现在,让我们更多地了解这些角色之间的区别:

图 3.4:企业架构师、技术架构师和解决方案架构师之间的区别
企业架构师负责与关键利益相关者协作,定义业务目标,并建立整个企业基础设施(如软件和硬件),以满足组织的需要。他们主要专注于实施和管理针对关键和战略业务目标的复杂 IT 解决方案。
同时,解决方案架构师在组织内部扮演着实际的角色。他们收集业务需求,然后分析它们,最后将它们转化为一个使用公司标准和技术栈的新软件解决方案。
技术架构师主要负责监督解决方案的技术架构和实施中使用的核心技术。他们的主要职责是为开发团队提供技术领导,并决定软件解决方案的每一个技术方面。
以下图表描绘了一个提供数字化转型服务的企业中企业架构栈的结构:

图 3.5:企业架构栈
通过拥有解决方案架构师,公司能够主要创建一个稳固的结构,使公司的愿景和目标与各种技术保持一致。
摘要
在本章中,我们提供了关于解决方案架构的快速介绍。然后,我们学习了成为有效的解决方案架构师所需的某些基本个性和软技能。在本章的后面部分,我们强调了在项目开发生命周期中应避免的一些常见陷阱。最后,你了解了企业架构师、技术架构师和解决方案架构师之间的区别。
在下一章中,我们将深入探讨解决方案架构的原则,你将了解七种流行的 UML 图,这些图将帮助你建模你的解决方案架构。
第二部分:设计解决方案架构
在本节中,我们将讨论解决方案架构的关键原则,并深入探讨最常用的 UML 图及其具体示例。然后,我们将了解使用 UML 创建和设计架构的过程。
之后,我们将探索关键架构模式和如何为我们的解决方案选择正确的模式。此外,我们将探讨解决方案架构的设计和运行时质量属性。在本节的后面部分,我们将深入研究安全考虑事项以及如何保护我们的 ASP.NET 解决方案,然后我们将讨论主要的测试类型以及在此方面的最佳实践。
本节包含以下章节:
-
第四章, 设计解决方案架构
-
第五章, 探索架构设计模式
-
第六章, 架构考虑事项
-
第七章, 保护 ASP.NET Web 应用程序
-
第八章, 在解决方案架构中进行测试
第四章:第四章:设计解决方案架构
在上一章中,我们了解了一些构建你的潜力并成为有效解决方案架构师所需的必要特质和技能。我们还快速概述了什么是解决方案架构。
在本章中,我们将开始更加关注解决方案架构的实践。特别是,我们将探讨解决方案架构的关键原则,并研究在设计中等规模到大型解决方案时推荐使用的流行统一建模语言(UML)图。
在本章中,我们将涵盖以下主题:
-
探索解决方案架构的关键原则
-
通过具体示例深入研究最常用的 UML 图
-
通过 UML 创建设计架构的过程
到本章结束时,你将丰富你对流行 UML 图的知识和理解,并学会如何在设计中使用它们。此外,你还将了解解决方案架构的关键原则以及它们如何影响你的设计过程。
探索解决方案架构的关键原则
架构原则概述了设计、构建和部署成功软件解决方案所需的基本程序和指南。它们旨在影响你的架构方法并提高解决方案的质量属性。
有许多原则我们可以采用在我们的工作方法中准备设计架构。如果我们认为它们将为架构设计增加价值或如果我们认为它们将有效地提高设计过程,我们甚至可以定义我们自己的原则。最重要的是,我们需要确保我们提供理论与实践之间的良好平衡,并采用实用且强大的原则,以推动我们解决方案架构中的商业和技术变革。
通常,我们应该为我们的解决方案架构实践设定 10 到 20 个指导原则。确保你不会有太多的原则。这是因为它们变得难以记忆和难以应用,这将限制我们架构的灵活性。在这种情况下,最好保持它们简单和专注。
有一种标准方式和推荐格式,你可以用来定义架构原则。通常,一个原则分为四个主要部分:
-
名称:名称应反映原则的核心价值。它应该是简单且易于记忆的。
-
描述:描述是一句明确定义和解释原则的陈述。
-
理由:理由是一句强调遵守原则的商业效益的陈述。它也可以解释与其他原则的相关性。
-
影响:影响应突出采用此原则所需的技术要求和业务要求。
这些元素旨在支持对每个原则的理解,并证明其在解决方案架构中的应用合理性。
我们所采用的原则应属于特定的类别或领域。根据 开放集团架构框架(TOGAF),架构原则广泛分为四个领域:
-
商业原则:这是一套关注解决方案商业方面的指导方针。
-
数据原则:这些定义了管理和结构化数据的标准指导方针。此外,它们还强制执行一系列安全措施,以保护解决方案资产。
-
应用原则:这些涉及应用程序的属性,如性能、用户体验以及模块或子系统如何相互交互。
-
技术原则:这些详细说明了对于解决方案成功和持续运行所必需的技术指导方针和需求。
小贴士:
TOGAF 是一个框架和方法,旨在提供一种高级方法来设计和构建企业信息技术架构。您可以在
pubs.opengroup.org/architecture/togaf9-doc/arch/chap20.html了解 TOGAF 对架构原则的定义。
)
这里有一个突出解决方案架构关键原则的插图。您可以看到,四个领域正在将不同领域的设计指导方针合并在一起,以产生一个灵活、可扩展和可重用的解决方案:

图 4.1:.NET 解决方案架构推荐的关键原则
在接下来的章节中,我们将探讨您真正需要了解的前述原则。我们可以直接采用这些原则,或者根据我们的需求添加、修改和删除一些原则。然而,始终记住,原则的目的是为了使我们所提出的解决方案受益,而不是增加任何障碍或复杂性。
商业原则
解决方案架构,包括所有开发成果及其质量,至关重要。然而,我们不应只关注项目计划、进度和结果。记住,你构建解决方案的原因是为了解决商业问题。因此,解决方案架构与商业目标和目标保持一致是必须的。在接下来的章节中,我们将讨论应考虑的三个商业原则。
最大化对企业的利益
所有架构和信息管理决策都必须以确保对整个企业带来最大利益的方式进行。例如,解决方案应为企业内的所有实体带来长期价值,而不仅仅是针对一个部门或小团体。这一原则鼓励以自我为中心的高效协作。
信息管理是每个人的事
所有关键利益相关者、商业专家和技术团队都负责作为一个委员会协调一致,以定义解决方案的商业目标,并确保它们与企业目标一致。本质上,这个委员会的每个人都负责在自己的部分中构建和管理解决方案。
业务连续性
在系统故障的情况下,解决方案架构应确保企业的业务连续性。简单来说,任何类型的系统故障,包括硬件、软件和数据损坏,都不应影响业务活动和运营的连续性。例如,解决方案设计应建议最先进的恢复机制、系统冗余或故障转移备份计划,以在灾难情况下平滑业务功能的运行。关键利益相关者应定义解决方案对企业运营的重要性,并决定应应用哪种故障转移计划以确保业务连续性。
数据原则
数据是业务流程的重要组成部分;它是赋予企业利益相关者根据关键指标和绩效指标做出战略决策的有价值资产。在设计构建软件解决方案时,应考虑以下三个数据原则。我们将逐一探讨它们。
数据是资产
虽然许多架构师已经知道这个原则,但我们仍然发现数据并没有像应该的那样被高度重视。数据是组织的核心商业资产。因此,解决方案的设计应确保以高安全措施正确存储、管理和检索数据,以更好地保护。
数据是共享的
存储在集中式存储库中的准确数据是软件解决方案的支柱,及时访问这些数据对于提高使用该解决方案的决策者的效率非常重要。此外,商业用户需要数据来执行他们的日常职责。因此,你的解决方案设计应允许根据用户的访问权限及时访问数据。
数据安全
软件解决方案应确保数据的完整性和机密性。它应保护数据并禁止未经授权的访问或非法处理。有许多数据政策旨在保护数据;我们需要根据我们的目标用户遵守这些政策。例如,如果我们正在构建针对欧洲公民的软件解决方案,那么遵守通用数据保护条例(GDPR)是必须的。
应用程序原则
现代应用程序的指导原则正在演变。它们应该是动态原则;记住,过去适用的原则在今天的架构中不再相关。始终寻求改进您采用的原则,并使其成为一种持续现象。以下是一些真正重要的原则,它们在交付现代和高效应用程序方面产生了影响。
易用性
应用程序应易于使用、直观且美观。我们应该拥抱简洁;这是因为应用程序越容易使用,就越有可能被我们的最终用户采用。始终将用户放在首位;他们希望使用能够帮助他们工作并使其在短时间内变得高效的应用程序,而无需花费大量时间学习它,在他们开始从中获得价值之前。
优化应用程序速度
我们生活在数字化转型时代;用户正在寻找实时响应的应用程序。因此,应用程序的速度是一个重要的考虑因素,因为它可以影响整个用户体验。
技术原则
我们的技术原则应始终遵循最新的技术趋势。现代化公司的技术平台和开发实践非常重要。这将使您能够设计现代的数字解决方案。让我们探讨在任何 .NET 开发团队中应采用的三个原则。我们将在下面列出。
致力于云原生未来
云原生应用已被证明是软件的未来。我们试图构建的解决方案可以受益于云中托管的平台、服务和流程。例如,Azure 服务具有高度可扩展性、易于修改和连接性,这使得我们能够通过更少的编码来扩展应用程序的功能。
使用 .NET Core (.NET 5 或更高版本)
.NET Core 的最新版本被称为 .NET 5。它是一个免费且开源的框架,可用于构建任何类型的应用程序。它是一个跨平台框架,继承了常规 .NET 框架的所有重大优势。.NET Core 的一个关键改进是性能,因此在构建新解决方案时考虑使用此框架。
自动化重复的开发任务
准备解决方案的发布可能耗时,尤其是如果您旨在发布多个构建和热修复。您可以规划自动化作业以最小化此类任务中所需的手动干预,利用 DevOps 工具来自动化构建和测试计划。
在本节中,我们学习了在您的解决方案架构中应采用的关键原则。这些原则为解决方案的四个主要方面提供了指导:业务、数据、应用和技术。应用这些原则将使您能够交付一个坚实、可扩展、可重用且易于维护的解决方案。
在下一节中,我们将探讨在设计和软件解决方案时应使用的六个流行 UML 图。
学习使用 UML 模型软件架构
UML 是一种标准图形表示法,允许我们可视化软件解决方案的规范和设计架构;这是一种简化我们与解决方案利益相关者沟通架构的方式。UML 的目的是为开发团队和业务分析师提供一个统一的设计建模符号,使他们能够用简化的图表解释复杂的企业流程。此外,它使我们能够构建和可视化不同的软件组件以及它们之间的关系,这定义了整个解决方案的设计架构。
UML 图分为两类:结构图和行为图。结构图强调系统的静态视图。它们用于可视化软件的不同组件和对象。主要来说,它们描述了系统中包含的内容。
行为图强调系统的动态视图。它们通过描述软件支持的过程和功能来可视化业务规范。主要来说,它们描述了系统中必须发生的事情。
下面的图显示了不同的 UML 图类型:

图 4.2:UML 图类型列表
在接下来的章节中,我们将探讨最常用的图。尽管我们可以使用许多不同类型的 UML 图来建模解决方案架构或描述系统功能,但我们将探讨大多数架构师经常使用的流行 UML 图,以记录软件解决方案的不同方面。它们如下列出:
-
组件图
-
类图
-
序列图
-
状态图
-
活动图
-
包图
-
用例图
我们将学习何时使用每个图,并探讨每个图的不同符号和表示法。然后,我们将检查每个图的示例。让我们从学习这些图开始。
组件图
UML 组件图用于图形化表示软件系统中的不同模块和组件,包括这些模块之间的关系和交互。模块是一组提供不同功能但被分组到一个业务流程中的类或接口。
组件图的好处
组件图可以通过以下方式帮助您:
-
可视化软件系统的整体物理结构
-
描述系统的组件及其相互关系
-
根据共同的服务目标对面向对象的类进行分组
-
模拟系统的 .NET 源代码或数据库
组件图的符号和表示法
这里列出了用于绘制组件图的不同形状和符号:

图 4.3:组件图的符号和表示法
购物系统的组件图
假设我们想要构建一个简单的在线购物解决方案。我们将使用组件图来描述该系统中的不同组件。
首先,我们需要通过根据其目的对功能需求进行分组来识别这些组件。在这个例子中,我们有三个组件:
-
订单
-
客户账户
-
产品库存
接下来,我们需要识别和可视化这些组件之间的关系。为了下订单,客户应提供必要的输入以完成订单。这就是为什么我们需要使用接口符号将订单与客户关联起来的原因;然后客户应从库存中选择一个或多个产品。这将确保订单与产品完全关联。因此,我们将使用依赖符号将订单与产品关联起来。以下是一个描述三个组件及其交互的组件图示例:

图 4.4:在线购物 UML 组件图
注意,您可以使用组件图来展示源代码中的物理文件。这在进行正向或逆向工程以识别源代码文件集时非常有帮助。此外,您还可以使用组件图来模拟物理数据库。
类图
UML 类图用于通过图形化表示类及其属性和操作来描述面向对象系统的结构,包括这些类之间的关系。
类图的好处
类图在软件工程师中非常受欢迎。它们非常强大,当你想要描述软件系统内的面向对象类时非常有用。我们可以使用 UML 类图来完成以下任务:
-
使用结构特征(属性)和行为特征(操作)描述系统中的每个类。
-
绘制类之间的关系,例如抽象和关联。
-
可视化系统的数据模型。
-
从业务角度创建软件的详细模型,这对非技术利益相关者了解系统的总体概述非常有帮助。
-
从类图中生成C#源代码。
类图的符号和表示
类图简单易读。以下是一个示例类图,以帮助你理解不同的符号:

图 4.5:一个示例类图
如你所见,标准的类符号由三个部分组成:
-
上半部分包含类的名称。
-
中间部分包含类的属性/成员及其类型。
-
下半部分包含以列表格式显示的类方法。
有不同的可见性符号用来指示类中包含信息的访问级别:

图 4.6:C#访问修饰符及其在 UML 中的符号
我们可以使用基数符号来定义两个类之间关系的类型。例如,一个客户可以有一个或多个订单(即一对多关系),而另一个订单可以有一个客户(即一对一)。以下表格显示了不同的基数符号:

图 4.7:基数类型
类之间存在不同类型的关系。以下表格显示了这些关系的符号:

图 4.8:类之间的关系类型
在线购物系统的类图
在在线购物系统的组件图部分,我们可视化了在线购物系统的组件图。在本节中,我们将展示该系统的类图:

图 4.9:一个在线购物系统的类图
如你所见,每个框代表一个类在标题中。我们应该提供类名,然后列出类的所有属性和方法。类之间的交互通过线条来可视化。我们称之为关系。
类图可以在软件的整个生命周期中使用,从可视化软件的高级概念开始,然后是在创建详细理解规范时,最后是在软件实现过程中。类图是一种基本的建模技术,用于可视化系统中所有的面向对象对象,因此请确保你掌握了它。
序列图
时序图用于记录业务或逻辑过程。它展示了在过程执行期间对象之间交换的事件和消息的流程。因为它可以描述软件支持的使用案例或操作,所以被认为是一个交互图。
这种交互操作可以发生在用户与您正在构建的软件之间,或者发生在您的软件与其他系统(如中间件集成)之间,或者发生在同一软件的子模块之间。例如,我们可以使用时序图来解释我们系统中的认证机制,或者说明酒店预订系统的预订流程。
时序图的优点
时序图在描述复杂操作或用例时非常有帮助。您只需突出显示涉及的对象、操作步骤的顺序以及从过程开始到完成交换的消息。如果您想执行以下操作,可以使用时序图:
-
解释具有多个步骤的复杂用例。
-
在操作期间建模对象和组件之间的交互。
-
展示您系统与另一个第三方系统之间的集成流程。
时序图的符号和符号
以下表格列出了您必须知道的基本符号和符号,以便创建时序图:

图 4.10:时序图的符号和符号
在下一节中,我们将创建一个时序图。
购物车时序图
在以下示例中,我们展示了一个在线购物过程的示例用例的简单时序图。该图包括以下生命线:
-
想要从在线系统中购物的客户。
-
购物车界面,它保存了用户想要购买的项目。
-
订单模块,它处理用户请求并确认支付。
该过程使用以下时序消息进行描述:
-
用户可以向购物车添加产品。
-
用户可以从购物车中移除产品。
-
用户可以调整项目数量。
-
用户可以看到所选项目的总价。
-
用户可以确认订单。
以下图包含一个循环片段,允许用户在确认最终订单之前向购物车添加更多产品或项目:

图 4.11:购物车处理时序图
在下一节中,我们将了解状态图。
状态图
状态图(或状态机图)通常在您想要描述系统如何表现和响应时很方便。它是状态、转换、事件和活动的组合。它用于模拟特定功能的流程,并显示从一种状态到另一种状态的所有转换。它还可以描述单个对象,并说明该对象如何响应系统中的一系列事件。实体的状态由其属性的值定义,这些值由特定时间发生的特定事件控制。
当您希望模拟接口、类或协作的行为以及由特定事件触发的业务流程时,状态图非常有用。它还有助于通过消除不必要的步骤和识别应添加到流程中以使其更有效的缺失步骤来改进流程。
状态图的优点
状态图用于描述事件如何改变过程的行为。我们可以使用状态图来完成以下操作:
-
可视化系统的动态视图。
-
在业务流程场景中模拟状态流。
-
使用对象从一步移动到另一步时的状态来解释事件驱动的过程。
-
展示系统中的交互功能。
状态图的符号和记号
下表列出了您必须了解的基本符号和记号,以便创建状态图:

图 4.12:状态图的符号和记号
在下一节中,我们将使用这些符号来绘制状态图,以描述双因素认证过程。
双因素认证过程的状态图
在以下图中,我们描述了双因素认证过程的事件以及从一个状态到另一个状态的转换:

图 4.13:描述认证过程的状图
前面的图显示了用户提供登录凭证后发生的第一事件。然后,系统验证凭证,如果凭证有效,则将认证令牌发送回用户;否则,要求用户再次输入有效凭证。之后,用户应提交令牌供系统验证,系统将决定如果令牌有效则完成登录过程;否则,要求用户重新输入令牌以继续。
活动图
UML 中的重要图之一是活动图。在说明系统的动态视图方面,它与状态图类似。活动图是描述系统内对象之间从一项活动到另一项活动的控制流流程图。它主要用于建模业务流程。活动图中描述的活动可以是顺序的也可以是并发的。
活动图的优点
活动图是一种有用的流程图,描述了系统中流程执行的活动。活动图可以帮助我们做到以下几点:
-
通过描述所有活动来解释用例场景的步骤。
-
学习特定算法的逻辑。
-
思考并建模业务流程和工作流程。
活动图的符号和表示法
在开始创建活动图之前,您必须了解其符号和表示法。以下表格列出了活动图的主要符号:

图 4.14:活动图的符号和表示法
在下一节中,我们将查看一个活动图的示例。
ATM 系统的活动图
在以下示例中,我们使用活动图描述了一个 ATM 系统的基本流程:

图 4.15:ATM 系统的活动图
如您所见,前面的图描述了 ATM 交易的过程。它从插入卡片并输入 PIN 码开始。最初,服务器将验证 PIN 码。如果有效,则服务器将建议 ATM 允许客户继续操作,输入取款金额并完成交易;否则,卡片将被弹出。
包图
使用包图的主要目的是通过可视化各种层及其依赖关系来描述我们系统的整体逻辑架构,其中一层代表一组类。系统中的物理组件根据其在系统中的角色和执行的任务分组到层中。在单个层内创建嵌套层,可以描述主要组件的高级细节。
在定义系统中的主要层之后,我们需要可视化层之间的依赖关系或关系。这将描述层之间正在发生的交互。
包图的优点
通过将主要组件统一到层中,包图可以使我们的架构易于理解。我们可以使用包图来帮助我们执行以下任务:
-
解释系统的高级逻辑架构和结构。
-
可视化设计的主要组件或功能单元及其相互依赖关系。
-
识别将您的系统与第三方系统集成可能性的可能性。
-
发现可能导致您的系统无法演变的架构中的差距。
-
在可能影响多个层的主要变更情况下,传达所需的工作量。
-
与开发团队就预期架构达成一致。此图为您提供比较您的架构与开发过程中实施的内容的能力。
包图的符号和表示法
以下表格列出了包图的主要符号:

图 4.16:层图的符号和表示法
在下一节中,我们将检查典型 ASP.NET Web 解决方案的包图。
ASP.NET Web 解决方案的包图
在以下图中,我们使用包图来描述典型 ASP.NET 解决方案的高级架构,而不提及每个包中类和资产的具体细节:

图 4.17:典型 ASP.NET 解决方案的包图
在前面的图中,我们已经表示了 ASP.NET 解决方案的多层架构中的包。表示层包括解决方案的用户界面,服务层代表一个中间件服务,为 Web 和移动应用提供高级通信服务。业务层包含所有业务逻辑和实体。至于数据层,这包括访问存储在数据库中的数据的方法。
用例图
软件工程中最激动人心的时刻之一,就是您正在设计和开发的产品满足客户需求的那一刻。没有比拥有清晰的用例更好地达到这个目标了。用例对于从客户的角度描述产品至关重要。有两种类型的用例:文本和视觉。
在第一章《软件开发生命周期原理》中,我们学习了文本用例及其准备方法。在本节中,我们将介绍用例的可视化表示。
用例图用于可视化用户需求;更具体地说,它用于可视化系统行为以及用户与系统之间的交互。
用例图的好处
用例图是一种简单而有效的技术,可用于可视化用户与系统的交互。它不显示所有详细用户需求,而只显示用例的交互。用例图可以通过以下方式帮助您:
-
阐述用户与软件的交互
-
可视化系统的功能需求和范围
-
显示用例的高级步骤
-
将用户需求与实现相匹配并支持测试用例的生成
用例图的符号和表示
用例图的符号简单直接。以下表格列出了用例图的主要符号:

图 4.18:用例图的符号和表示
客户与 ATM 之间的用例图
在以下图中,我们创建了一个用例图来描述 ATM 系统支持的主要功能,包括与客户的交互:

图 4.19:ATM 系统的用例图
在前面的图中,参与者是使用 ATM 系统并尝试进行身份验证以完成交易的客户。彩色椭圆表示系统支持的功能,而线条表示块之间的关联和交互。
在本节中,我们学习了最常用的 UML 图,这些图对于记录解决方案的许多方面至关重要,例如解决方案设计、面向对象的系统结构以及业务和逻辑流程。我们还学习了我们的系统如何行为和响应用户交互,系统对象之间从一项活动到另一项活动的控制流,系统的高级逻辑层及其依赖关系,以及从客户的角度看的需求。
在下一节中,我们将学习如何使用 UML 创建解决方案架构。
使用 UML 设计架构
到目前为止,我们已经了解到 UML 图是软件的单个简化表示。我们需要构建各种 UML 图来理解系统的完整方面,并将我们的架构设计传达给利益相关者和不同类型的用户。将这些 UML 图分组到逻辑子集中,将创建系统的特定视图。架构设计是通过五个视图的集合来表示的。这些视图如下:
-
用例视图:用例视图是所有其他视图的焦点,因为它包括了用户需求,包括所有系统功能。没有这个视图,就无法构建其他视图。
-
设计视图:设计视图旨在说明在用例视图中定义的功能如何在系统中以类及其关系的形式设计。这个视图主要是由 UML 类图来描述的。
-
实现视图:实现视图描述了系统的核心组件及其之间的交互。它主要是由 UML 组件图来表示的。
-
过程视图:过程视图描述了系统支持的流程。它通过汇聚系统的性能、可扩展性和吞吐量来实现这一点。它主要由 UML 类图表示,类似于设计视图,但专注于参与流程的活跃类。
-
部署视图:部署视图通过关注系统拓扑、分布、交付和安装来描述系统的部署。它由 UML 部署图表示。
以下图示展示了五个视图,其中用例视图位于中心,并与所有其他视图相连:

图 4.20:系统架构视图
下表总结了架构视图,以及相关的 UML 图,以帮助理解系统的不同方面:

图 4.21:系统架构视图及其相关的 UML 图
解决方案架构师负责创建这些视图及其相关图的第一版,并处理构建解决方案架构的更新。整个解决方案架构被用于影响和指导项目生命周期中的开发活动。
摘要
在本章中,我们探讨了设计、构建和部署软件解决方案所需的基本程序和指南的关键原则。此外,我们还学习了必要的 UML 图,并通过实际例子说明了每个图中不同元素及其益处,以及何时使用它们。在本章的后面部分,我们探讨了使用 UML 构建解决方案架构所涉及的过程。
在下一章中,我们将深入探讨核心架构模式。我们将重点关注微服务架构,并学习如何为特定解决方案选择正确的模式。
第五章:第五章:探索架构设计模式
在上一章中,我们学习了解决方案架构的关键原则。我们还探讨了最常用的 UML 图以及何时使用每种图来创建解决方案架构的视图。
在本章中,你将了解你必须知道的顶级架构模式,以构建坚实的软件架构。
在本章中,我们将涵盖以下主题:
-
介绍架构模式
-
探索关键架构模式
-
学习如何为你的产品选择正确的模式
到本章结束时,你将了解架构模式。我们将通过探索顶级架构模式和示例用例来丰富我们的知识。此外,我们还将解释在选择适合我们软件产品的正确架构模式时应关注的准则。
在我们开始学习这些模式之前,首先,让我们了解架构模式实际上是什么。
介绍架构模式
架构模式是对我们在不同的商业行业和不同场合可能遇到的一般问题的可重用解决方案架构。它提供了一套预定义的指南和规则,以建立解决方案的底层结构。
重要的是不要混淆 .NET 设计模式和架构模式。前者代表了一种组织类的方法,可以使你的源代码更可靠、可扩展且易于维护,这将解决我们系统中特定组件或模块内部的各种问题。相比之下,后者在整个解决方案中具有更广泛的范围,因为它定义了解决方案的高级抽象结构。作为解决方案架构师,你必须了解这两种模式:
-
设计模式使用面向对象原则开发类。
-
架构模式有助于定义和维护整个系统的整体结构。
下面的图显示了作为解决方案架构师你可能需要做出的不同层次的架构决策:

图 5.1:架构决策的各个层次
在前面的图中,你可以看到选择架构模式是你必须最早做出的决定之一。随后,你应该选择将用于构建产品的正确技术栈。之后,你需要决定应用程序的类型以及将帮助你组织代码并使其可重用和可扩展的设计模式。
现在,让我们从了解最流行的架构模式开始。
流行的架构模式
在本节中,我们将探讨五种流行的架构模式。我们将解释每种模式的核心理念,然后概述每种架构模式的关键组件。这应该有助于你了解架构模式的有用性,并支持你为提出的解决方案选择正确的模式。让我们从分层架构开始。
分层架构
这种架构在大多数建筑师和开发者中广为人知,被称为n 层架构。它用于将系统结构化成不同的层,每一层都由一组基于特定上下文分组在同一个组件中的类组成。这些层是水平结构的,以便每一层都可以消费来自它自己或其下多个层的服务。
在大多数情况下,这种架构由三个主要层组成,如下面的图所示:

图 5.2:典型的 3 层分层架构
如前图所示,这些是三个主要层:
-
表示层:这一层代表负责通过页面、菜单、按钮、链接、报告、表单等方式处理所有用户交互的组件。它包含所有图形设计,并定义了应用程序的外观。它是唯一对最终用户可见的层。
-
业务层:这一层包含业务逻辑、业务规则和实体,它们定义了整个解决方案的行为。
-
数据访问层:这一层包含负责操作数据库层的代码,这是所有数据存储的地方(例如,SQL Server、Oracle和MongoDB)。
以下截图显示了使用Razor Web 应用和.NET 5类库在Visual Studio中实现的 3 层架构:

图 5.3:Visual Studio 中的 3 层架构
在前面的示例架构中,数据访问层是最低层,不引用任何其他层。它应该包含操作数据库表的ADO.NET调用或EntityFramework调用。
业务层引用数据访问层。它应该包含所有业务逻辑和实体;在这里,实体代表映射到数据库表的业务对象。至于表示层,这是包含用户界面的Web 应用。它引用业务层,不允许直接调用数据访问层。Web 应用可以是 MVC 应用或 Razer 应用,因为可以混合这两种模式来构建解决方案。
在下一节中,我们将更详细地了解表示架构。
表示架构
在解决方案的用户界面(UI)中,我们可能会遇到的一个主要问题是存在难以维护和扩展的杂乱代码。我们在许多网络表单解决方案中都看到了这种情况。这使得架构展示模式变得极其重要,因为它通过清晰的职责分离和低耦合来组织源代码,从而消除了任何复杂性,并使 UI 代码井然有序且易于管理。
这种架构模式有助于解决主要的 UI 问题,如与 UI 耦合的逻辑、状态管理以及 UI 元素与业务实体之间的同步。
如以下图表所示,有三种类型的展示模式:

图 5.4:各种展示模式类型
所有这些模式都侧重于将 UI 与逻辑解耦,从而允许有整洁的HTML标记。让我们在接下来的部分中探索这三种类型。
MVC(模型,视图,控制器)
MVC 模式让你完全控制标记。它非常受欢迎,Visual Studio 已将其作为创建新ASP.NET项目的默认模板。它将应用程序分为三个主要组件:
-
模型:这封装了业务逻辑并包含要在视图中显示的数据。
-
视图:这通过 UI 显示内容。
-
控制器:这处理用户交互,与模型一起进行数据更新,最后选择一个视图来渲染内容。
以下图表显示了三个主要组件,并说明了哪些组件引用了其他组件:

图 5.5:MVC 模式
下面是一个使用Visual Studio 2019和.NET 5的 MVC 项目模板示例:

图 5.6:Visual Studio 中的典型 MVC 项目模板
在前面的示例架构中,你可以看到三个组件封装在同一个项目中,但存在于不同的文件夹中。你也可以为每一层创建一个单独的项目,然后配置引用。
MVP(模型,视图,演示者)
MVP 模式是一种 UI 展示架构,被认为是 MVC 模式的衍生。它将架构分为三个主要组件:
-
模型:这包含解决方案的业务逻辑。
-
视图:这包含封装数据属性的接口,我们将将其发送到或从 UI 接收。与 MVC 模式相比,它不包括 UI。
-
演示者:它从模型检索数据并将其绑定回视图。它作为模型层和视图层之间的中间层。
以下图表说明了 MVP 模式的三个主要组件:

图 5.7:MVP 模式
这里是 Visual Studio 中使用 Razor Web 应用 和 .NET 5 类库的 MVP 项目模板。检查项目之间的引用,以便了解三个组件之间的关系:

图 5.8:Visual Studio 中的典型 MVP 项目模板
在前面的示例架构中,你可以看到 UI 位于 Web 应用中,它引用了 模型、视图 和 演示者 层。视图层不引用任何其他项目。它包含在演示者层中实现的接口。模型层包含业务实体和业务逻辑;它不引用任何其他项目。至于演示者层,它包含在视图层中定义的接口的实际实现。因为它在它们之间扮演着中间角色,所以它引用模型和视图层。
让我们接下来探索第三种表示架构。
MVVM(模型、视图、视图模型)
这种架构也被认为是 MVC 模式的扩展。它也包含三个主要组件。它通过提供高可重用性和可伸缩性,结合了 MVC 和 MVP 的最佳优势。这种架构的关键概念是将逻辑从控制器移到 视图模型:
-
模型:这包含业务规则和模型类。
-
视图:这包含 UI。
-
视图模型:这是 视图 和 模型 之间的中间层。
以下图表显示了这三个组件以及它们如何相互交互:

图 5.9:MVVM 模式
注意 Session、ViewBag 或 TempData。
这里是一个使用 Visual Studio、MVC 和 .NET 5 的 MVVM 模式示例项目模板:

图 5.10:Visual Studio 中的典型 MVVM 项目模板
我们还可以使用 Razor Pages 项目模板,因为它遵循 MVVM 模式。这使得双向数据绑定成为可能,因为模型和控制器代码附加到 Razor 页面,从而允许以关注点分离的方式实现简单的开发体验。
理解这三种表示架构之间的区别非常重要,这样你才知道应该为你的解决方案使用哪种模式。
现在,让我们来了解干净的架构。
清洁架构
在 n 层分层架构中,我们了解到一切皆依赖于数据库层,这被视为一个传递依赖。清洁架构被认为是领域中心架构。业务逻辑和应用层是设计的中心。与 n 层架构中业务逻辑依赖于数据访问层的情况不同,清洁架构通过强制基础设施和其他层依赖于应用核心来反转这种依赖关系。
下面的图示展示了可以用来可视化这个架构的典型技术。它使用一系列同心圆,类似于洋葱的环:

图 5.11:清洁架构洋葱视图
在前面的图中,圆圈代表系统的不同组件,应用核心由实体和用例组成。影响这个架构的关键因素是依赖规则。它强制组件的依赖关系流向中心。内圈中的组件永远不应该依赖于外圈中的任何东西。
因此,如果我们在外圈声明一个函数或类,它不应该在内圈中可见。在图中,你可以看到依赖关系是如何从最外圈流向用例和实体所在的位置的。
让我们探索这个架构的关键组件:
-
实体代表业务规则,如对象和相关方法。
-
用例表示应用的核心,其中实现了系统的所有用例。它管理从实体到实体之间的数据流。这一层不受外部层(如数据库或 UI)可能发生的更改的影响。
-
接口适配器是包含 MVC 组件(如控制器、视图和演示者)的层。在这一层中,它扮演着中间角色,将来自用例和实体的数据转换为适合外部组件(如数据库和控制器)的格式。这一层的模型用作在用例和演示者或视图之间交换数据的数据结构。
-
框架和驱动器代表这个架构的最外层。这一层包含数据库和所有 UI 代码。
下面的图示展示了这个架构的水平视图:

图 5.12:清洁架构水平层视图
在此图中,存在两种类型的依赖关系,它们通过箭头的样式来表示。实线箭头表示编译时依赖,而虚线箭头则代表仅运行时依赖。用户界面层处理应用程序核心中定义的接口,但没有直接访问基础设施层中的实现。这些接口在运行时通过依赖注入绑定到具体的实现。
提示:
依赖注入是一种软件设计模式。这种模式的主要目的是允许你拥有松耦合的代码,支持如整洁架构这样的架构模式,以减少层之间的紧密耦合。它通过使用构建器对象初始化对象,然后在运行时注入这些依赖来替换类之间的硬编码依赖。
下面的截图显示了使用 Visual Studio、.NET 5 和 Angular 10 的整洁架构解决方案模板:

图 5.13:使用整洁架构的典型项目模板
让我们探索这个 .NET 解决方案中的每个项目:
- 最内层是
Domain项目。它不引用任何其他层,如以下截图所示。在右侧,你可以看到一个实体类的示例:

图 5.14:整洁架构中的实体项目
- 接下来,我们有
Application项目。正如你所见,它引用了Domain项目。它通过定义将在基础设施层中实现接口来包含所有应用程序逻辑:

图 5.15:整洁架构中的应用程序项目
- 接下来,我们有
基础设施层,它包含在Application层中定义的接口的具体实现。根据以下截图,你可以看到它引用了Application层:

图 5.16:整洁架构中的基础设施项目
- 最外层是
WebUI(请参阅 图 5.13)。这是一个单页应用程序,它使用Application层和基础设施层。
许多 .NET 解决方案模板支持这种架构,你可以在 GitHub 或 NuGet 上找到它们。你可以从 NuGet 下载其中一个模板,以开始使用整洁架构。以下截图显示了安装我们用来探索此架构的相同模板所需的 NuGet 命令行:

图 5.17:安装干净架构解决方案模板所需的命令行
在本节中,我们学习了干净架构及其主要组件。在下一节中,我们将探讨被认为是现代架构之一的微服务架构。
微服务架构
微服务架构允许你将解决方案划分为各种组件。每个组件完全独立于其他组件,并提供了特定的服务。以下图表显示了微服务架构:

图 5.18:微服务架构风格
根据前面的图表,你可以看到微服务架构由一系列独立的服务组成。每个服务都是自包含的,并且应在业务域内提供单一的业务能力。
让我们考察这种架构模式的特点:
-
微服务是小型、自治且松散耦合的服务。每个服务都有自己的代码库,并且可以由一个小型开发团队开发和维护。
-
每个服务应该是自包含的,并且单独部署。更新一个服务不需要你重新部署整个解决方案。
-
服务负责拥有自己的数据访问层,因为每个服务都有自己的私有数据库。
-
每个服务的内部实现对其他任何服务都是不可见且不可访问的。服务之间的通信是通过适当的 API 实现的。
-
客户端应用无法直接访问服务。通过 API 网关消费这些服务,它将调用转发到适当的服务。
以下截图显示了一个基本的微服务项目:

图 5.19:一个示例微服务项目
在前面的截图中,你可以看到一个被电子商务解决方案消费的订单微服务。这个微服务项目的核心组件如下:
-
Models:这些是包含映射到数据库字段的属性的数据实体。 -
OrderContext:这个类从实体框架DBContexts派生。它是实体订单和数据库之间的桥梁。 -
OrderRepository:这个类包含 CRUD 函数,例如GetOrder、CreateOrder和UpdateOrder。这个类应该实现IOrderRepository接口。 -
OrderController:这是一个从ControllerBase派生的类。它包含所有的 API RESTful 动作。 -
Docker:这是一个容器,它应该通过将所有依赖项捆绑成一个单一单元来简化微服务的部署和测试。它允许你在隔离的环境中运行微服务。
Web API 请求由OrderController类处理。控制器将调用存储库中的一个函数,该函数将使用DBContexts以及模型与数据库进行通信,以便返回、添加或编辑请求的数据。
在下一节中,我们将探讨面向服务架构。
面向服务架构
面向服务架构(SOA)允许您消费网络中可用的服务。其结构类似于 n 层架构;区别在于表示层不能直接调用业务层,也就是说,它只能通过服务来调用。以下图表显示了分层结构中的 SOA:

图 5.20:SOA
如您所见,服务层是一个位于表示层和业务层之间的抽象层。有了这一层,表示层就不需要直接与业务层通信。在这种情况下,您可以更改业务层而不会影响表示层。
微服务架构和 SOA 之间的区别是什么? 好吧,答案是范围。微服务架构是一种基于云的架构;它促进自治服务,这些服务是自包含的,针对应用范围。而 SOA 具有企业范围,每个服务不需要有独立的数据库。它可以处理多个业务能力;微服务则不同,它一次只处理一个单一的业务能力。
这里是一个列表,列出了支持您实现服务的.NET 技术(SOA):
-
.NET Web 服务:这是基于Web 服务描述语言(WSDL)(也称为XML Web 服务)。它是一个包含一组函数的服务层,这些函数使用标准化的 XML 消息系统。
-
Windows Communication Foundation(WCF):这是.NET 框架的一部分,用于构建面向服务的解决方案。通过使用 WCF,您可以从一个端点发送任何类型的数据,例如异步消息,到另一个端点。
-
ASP.NET RESTful Web API:这也是.NET 框架的一部分。它用于构建可以被任何类型的应用程序(包括 Web 和移动应用程序)消费的 HTTP 服务。
在本节中,我们探讨了可以帮助我们为我们的解决方案创建坚实基础的一些流行的架构模式。采用架构模式至关重要,因为它使我们的平台更具可扩展性,并提高了产品的整体性能。此外,它将防止代码冗余。
在下一节中,我们将探讨另一组您应该了解的架构模式。
探索其他架构模式
在本节中,我们将深入探讨一系列额外的架构模式,这些模式将使您能够执行高级可扩展性和系统解耦。我们将逐一研究每种模式,以了解其工作原理。这将帮助我们构建更优化的系统,其中包含可重用模块和有组织的结构,允许进行扩展。
服务器端无服务器模式
无服务器架构推广云平台和云原生代码。这是一种允许我们在第三方基础设施中托管解决方案的模式。使用这种方法,开发者将不再需要担心管理服务器软件和硬件。此模式允许我们将应用程序拆分为小型且自主的函数,这些函数可以单独触发和扩展。
以下图示说明了单页 Web 应用的无服务器架构:

图 5.21:Web 应用的无服务器架构
我们可以使用Azure无服务器基础设施来实现此模式。Azure 函数包括以下内容:
-
CDN:这代表内容分发网络。它缓存内容以获得更好的响应时间。
-
Azure Blob Storage:这允许您在微软的数据存储平台上存储大量非结构化数据。
-
Function App:这是一个事件驱动的模型,它提供了通过 HTTP 请求由客户端触发的自主函数的能力。请求的路由由 API 网关管理,将在下文中描述。
-
API Management:这是一个位于函数前面的 API 网关。它允许您将前端应用程序与后端中定位的函数解耦。使用这种 API 管理,我们可以在请求到达后端具体函数之前重写 HTTP URL 并管理请求。Azure API 管理还用于克服以下跨领域关注点:
a. 缓存 HTTP 响应
b. 监控和审计日志 HTTP 请求
c. 启用跨源请求共享(CORS),允许跨域访问
d. 强制执行策略,如检查 HTTP 请求并应用调用速率
e. 通过使用Auth2.0 授权与Azure Active Directory (Azure AD)强制执行认证机制来保护您的 API
-
Azure Cosmos DB:这是 Azure 提供的NoSQL数据库服务,用于构建现代应用程序。
-
Azure AD:这是常规活动目录的云版本。它用于验证用户。
-
Azure Monitor:它收集有关解决方案和资源使用的性能指标。
-
Azure Pipelines:这是由 Microsoft Azure 提供的另一项服务。它提供持续集成(CI)和持续交付(CD)服务,以自动构建、测试和部署您的代码到任何可访问的目标。
如果您希望实现微服务架构或想要扩展解决方案并从按需付费服务中受益,此模式非常完美。
客户端-服务器模式
客户端-服务器模式是一种涉及两种类型实体的网络架构:客户端和服务器。它用于有服务器扮演服务提供者角色,而多个客户端扮演服务消费者角色的场景。以下图描述了该架构背后的逻辑:

图 5.22:客户端-服务器架构
正如前图所示,客户端组件通过 TCP/IP 协议向服务器发送 HTTP 请求。请求被处理,服务器连接到数据库 服务器,然后向 客户端 发送响应。
事件驱动模式
事件驱动架构是另一种允许我们高度解耦应用程序的模式。它是一组服务的集合。每个服务异步工作,并在其数据更新时发布事件。客户端组件订阅事件以接收或发送更新。
假设我们正在构建一个电子商务解决方案,其中客户在提交订单时使用优惠券代码。系统必须确保同一客户只能使用一次优惠券代码。由于客户信息、订单数量和优惠券代码详情位于不同的数据库中,系统不能简单地验证优惠券代码的使用情况。解决方案是使用事件驱动模式来维护不同服务之间的数据一致性。
以下图显示了 Azure 事件驱动架构:

图 5.23:事件驱动架构
在前图中,请注意 HR 应用程序 如何订阅 员工事件,以及每个事件都有其自己的逻辑和数据库。
管道-过滤器模式
管道-过滤器模式由将复杂过程分解成一组较小任务组成。这种方法预计将提高我们应用程序的性能,以及每个任务的复用性和可维护性。单个事件触发一系列多个步骤,每个步骤执行特定的任务。以下图显示了使用管道-过滤器架构实现的示例过程:

图 5.24:管道-过滤器模式
Azure Data Factory 是此模式的良好示例,它允许您在云中创建数据驱动的自动化工作流,用于数据提取、分析和转换以及加载。
在本节中,我们探讨了一系列你应该了解的架构模式。每一种都提供了一种独特的实现方法,并为你的解决方案带来了关键优势。在下一节中,我们将学习如何在设计解决方案时选择正确的架构模式。
选择正确的模式
在前面的章节中,我们学习了主要的架构模式。然而,你可能已经注意到,在这一章中我们没有讨论一些模式。实际上,一些模式将在未来介绍。因此,你需要一种方法来分析一个模式,并决定你是否想选择它。你可能会被问到的一个问题是我们如何为我们的解决方案选择正确的模式? 让我们深入探讨这个问题。
架构设计是构建稳固和成功系统的基石。然而,在选择适合你解决方案的正确架构时,并没有一种适合所有情况的解决方案。当你想要决定使用哪种架构模式时,应该考虑各种不同的视角。
简而言之,选择架构模式的主要标准基于三个因素:
-
软件工程师(将参与项目):软件工程师应该熟悉你提出的架构。这样,他们可以轻松地导航解决方案结构,并根据需求开始实现新功能。然后,在产品交付的后期,他们应该能够清楚地了解如何修复任何缺陷以及哪些层需要修改。这是团队高效工作并交付成功稳定产品的一个重要因素。
-
客户: 从客户的角度来看,他们寻求的是在保持效率的同时,获得高质量的产品。此外,他们还希望确保实施后的架构能够在产品发布后支持额外的功能和修改。他们希望他们的产品具有良好的架构、可扩展性和易于维护。
-
产品类型: 注意,仅仅因为某个架构模式广受欢迎或流行,就选择它并不是一个好的做法。不要假设这样做会带来更好的产品。然而,架构模式的选择应该基于你的需求和我们要构建的解决方案类型。这将使你能够交付一个成功的产物。
我们已经探讨了应该影响你选择架构的三个主要因素。此外,这里有一个关键特征列表,当你选择架构模式时你应该考虑:
-
敏捷性: 我们应该考虑选择允许高度敏捷的架构,这有助于我们轻松拥抱和实施额外的功能和变更。
-
部署的便捷性: 我们选择的架构应该使我们能够轻松部署产品。
-
可测试性: 架构应该允许实现高可测试性。
-
性能: 这是一个重要的因素。架构应该允许实现高效率。
-
可扩展性: 架构必须允许我们扩展我们的系统,这意味着增加其容量。
-
开发简便性: 架构应该被开发者所熟知,以确保产品的开发和实施简便。它应该允许开发者在需要时对系统进行故障排除和修复缺陷。
可能导致系统完全失败的主要原因之一是选择了错误的架构模式。这就是为什么选择适合您系统的正确架构模式很重要,因为它将解决你在项目生命周期几个阶段可能遇到的各种问题。
摘要
在本章中,我们探讨了在许多解决方案中广泛使用的核心架构模式,以及一些现代模式,如清洁架构和微服务架构。我们还了解了一系列重要的架构模式,这些模式允许你进行系统解耦和可扩展性。最后,在本章中,我们探讨了在选择合适的架构模式时需要考虑的关键因素。
在下一章中,我们将深入探讨核心架构考虑因素,例如设计质量属性以及如何合理规划系统缓存、异常处理和部署。
第六章:第六章:架构考虑事项
在上一章中,我们学习了一系列你必须知道的架构模式,这些模式对于设计和构建一个成功的解决方案至关重要。这些模式是必不可少的,因为它们为开发团队设定了路径,并解决了与解决方案敏捷性、可扩展性和性能相关的客户关注点。在本章的后面部分,我们简要概述了一系列影响你选择正确模式的影响架构特性。
在本章中,我们将深入探讨应考虑的质量因素,例如可重用性、可用性、性能、安全性、开发时间和类似的质量要求。此外,我们还将了解规划异常处理、跟踪和部署的最佳实践。
下面是本章我们将涵盖的主题:
-
探索解决方案架构的设计和运行时质量属性
-
学习如何规划异常处理、跟踪和部署
-
网络应用程序中的缓存
在本章结束时,通过探索设计和运行时质量属性,你将了解到什么使得架构模式最适合你正在构建的产品。我们还将通过学习最佳实践来丰富你的知识,例如实施缓存以提升性能和整体用户体验,记录以在集中位置跟踪报告的错误,以及部署技术。
了解质量属性
一个有组织的解决方案架构为你的开发团队设定了正确的路径,并使得维护不同的质量特性变得容易,这将从许多方面进一步提升产品的质量。
在我们开始探索各种质量属性之前,让我们首先了解什么是质量属性。质量属性是定义系统质量的一个属性,它是系统的一个可测量或可测试的特征,用于指示所选架构如何满足客户的需求。质量属性有两种类型:可以在设计时测量的属性和可以在运行时或执行期间测量的属性。以下图表展示了我们将在本章中讨论的各种属性及其相应的类型:

图 6.1:软件架构质量属性
让我们在以下章节中探索这些质量属性。
探索设计质量属性
对于开发团队来说,产品的业务功能在重要性方面占据首位。我们经常专注于满足客户的职能需求,而在产品发布后,我们可能会注意到一些质量缺陷,例如产品难以维护或扩展。此外,我们可能会遇到性能问题或安全漏洞。在本节中,我们将探讨在软件架构阶段应解决的设计质量属性。
可维护性
可维护性是关键软件质量属性之一。它指的是架构支持产品行为未来变化的能力,例如引入具有新业务需求的功能或修改现有功能。
维修哲学也影响这一属性的测量,该属性指的是系统在故障后恢复所需的时间。我们的代码耦合度越高,组件开发中过度依赖性越强,产品就越难以维护。随着这一属性的存在,软件工程师开始将关注点分离的概念引入到架构中,例如在微服务架构中得到支持。
提高产品的可维护性可以极大地提升团队的生产力并降低添加新特性的成本。以下是一些提高可维护性的关键技术:
-
选择一种架构,通过低耦合来分离组件的责任,这应在系统中创建定义良好的层并简化系统中的变更。
-
使用接口来最大化系统插件模块的使用,这将允许更多的灵活性和可扩展性。
-
提供详细的文档来解释系统中的面向对象结构。
灵活性
灵活性指的是架构适应不同用户和系统需求变化的能力,这可能包括硬件变化、软件变化,甚至是业务规则的变化。你投入越少的精力来应对变化,它就越灵活;重新配置和部署系统越容易,它就越灵活。
一个灵活的软件架构能够适应变化,因此让我们检查以下提高灵活性的关键技术:
-
考虑使用业务层来封装业务规则。我们只能在业务规则发生变化时修改这些层。
-
考虑使用可配置的业务工作流引擎,例如Microsoft Power Automate。
-
考虑在系统中实现层,以将用户界面与业务逻辑和数据访问功能分离。
-
设计层次结构以保持一致性,并使其松散耦合,以最大化灵活性并促进组件的替换和复用。
可复用性
可重用性也是软件质量的关键属性之一。它指的是现有组件、类和函数可以被重用来开发新模块、新功能甚至新应用程序的程度。它消除了代码的重复,并最小化了实现新组件所需的时间。
可重用性是一种应该谨慎考虑其给系统带来的益处的应用方法。以下是一些提高可重用性的关键技术:
-
识别组件之间的横切功能,并实现我们可以跨不同组件重用的通用类和函数,以提供验证、日志记录、跟踪、授权和认证等功能。
-
考虑通过 Web 服务或 Web API 公开业务逻辑,以将此逻辑提供给不同的系统或平台,例如 Web 和移动设备。
-
使用可以通过不同组件访问的数据类型和结构。
集成性
集成性概述了组件通过作为整体系统架构一部分的信息交换而协同工作的方式。它还包括编码标准和命名约定,以及影响组件一致性的其他因素,使得开发者更容易理解代码并维护它。它还衡量了系统与其他系统集成的能力。
应用集成性以改善系统不同组件之间的和谐性有许多优势。以下是一些最大化集成性的关键技术:
-
强制执行预定义并可供开发团队使用的编码标准,并为整个系统架构提供详细的文档。
-
考虑使用 Web 服务或网关层与遗留系统集成。
-
进行代码审查会议,以确保在实施过程中遵守指南。
可测试性
可测试性是一个质量属性,它表明系统允许我们创建测试用例并执行测试计划以确定系统是否按要求工作的程度。它允许我们以有效的方式识别系统中的故障,并基于预定义的测试用例。
我们应该尽早发现缺陷、性能问题和安全漏洞,因为这比在产品发布时让客户发现它们要便宜得多。让我们了解一些提高可测试性的关键技术:
-
在Visual Studio中创建测试用例,然后运行测试计划并检查测试结果。这也适用于Azure DevOps。
-
在测试用例中使用模拟对象来构建不同的场景。
-
让我们的架构支持模块化组件,以便进行详细的测试。
-
创建单元测试以测试系统中的每个单个功能。
建议持续提高我们的学习曲线并提升我们的技能,以确保我们能够应用所有这些设计属性。这将导致创建平衡且高度高效的软件解决方案和产品。
在下一节中,我们将探讨运行时质量属性。
理解运行时质量属性
运行时质量属性是一组在系统在实际场景中执行期间测量的属性。它们代表了一组有助于测量软件产品性能和安全性以及其他质量约束的功能。
必须评估这些质量属性,以便主动采取行动,确保它们得到适当维护,从而向最终用户提供优质的产品。以下是对每个运行时质量属性的介绍,以及一些关键技术,深入探讨应考虑的改进细节。
性能
性能是每个客户端最重要的质量属性。它指的是系统在给定约束(如时间、准确性或内存使用)下执行特定功能的响应性。它包括两个指标,即延迟,这是对系统中触发的事件做出响应所需的时间,以及吞吐量,这是在给定时间框架内可以发生的事件数量。
我们都知道,有些产品由于性能问题而未被使用。因此,让我们了解一些提高性能的关键技术:
-
考虑使用异步调用。
-
使用数据传输对象(DTOs)来最小化从服务器发送到前端客户端的数据大小。
-
避免比必要的更频繁地检索数据,并在返回数据集合时使用分页。
-
使用性能分析工具,例如Visual Studio 诊断工具来识别对性能有重大影响的代码。
-
最小化前端资源,如JavaScript和CSS文件。
-
考虑使用Azure 函数来处理长时间运行的请求,因为进程外函数有助于最小化 CPU 使用。
-
通过使用 HTTP 压缩来减小 HTTP 响应的大小。
-
总是使用 ASP.NET Core 的最新版本,因为它包含许多改进。
安全性
安全性是系统的基本组成部分。它指的是任何系统都应受到保护,防止数据泄露和未经授权的访问尝试。确保系统安全始于实施适当的身份验证和授权机制。此外,防止系统资产被未经授权的修改也是必须的。这就是为什么我们应该始终部署编译后的程序集,而不是直接上传.NET 类。
为了保护我们的系统,我们必须深入了解我们想要部署产品的环境,我们需要授予用户什么类型的访问权限,以及他们可以访问什么。重要的是要知道,我们需要应用各种机制来提高保护级别。
我们对潜在威胁了解得越多,采取的行动就越能避免它们,我们就越能保护系统。定期对产品进行安全漏洞测试是防止可能损害客户声誉和损害其品牌信誉的数据泄露的必要措施。让我们检查以下关键技术,这些技术应该有助于我们提高产品的整体安全性:
-
创建一个定期任务来备份数据库和系统资产,并将它们存储在安全的位置,这样在需要时可以快速恢复。
-
测试恢复过程以确保备份能够正常工作。
-
应用稳健的认证和授权流程。
-
永远不要信任用户输入,始终验证数据输入,并使用存储过程来防止SQL 注入。
-
永远不要使用字符串连接来创建 SQL 语句。
-
对数据库中保存的密码进行编码。
-
不要在隐藏字段中存储敏感数据。
-
实施审计日志功能以记录系统中的每一个事件。
-
如果系统对客户来说是至关重要的,考虑实施集群服务器架构。
可靠性
可靠性是指系统在不需要进行维修或修改的情况下,随着时间的推移能够执行所有由用户触发的任务和事件的能力。系统在运营的早期阶段具有较高的可靠性概率。这个概率会随着时间的推移而开始降低。提高系统的可靠性需要我们识别最重要的用户旅程,然后分析它们以检测我们可以改进的区域。这种方法将使我们能够创建关于对用户最重要的服务和功能的指标。
这个质量属性对于系统提供的服务连续性至关重要。以下是一些提高我们系统可靠性的关键技术:
-
跟踪我们系统中使用最频繁的服务性能,以识别性能不佳或故障。
-
审计对 Web API 和 Web 服务的调用。
-
考虑实施故障转移计划。
-
考虑分析客户投诉以排除故障并确定应改进的服务。
可用性
可用性是一个评估系统用户界面的质量属性。它显示了使用系统的难易程度。如果用户不喜欢设计或者发现很难找到他们想要的东西,他们可能会停止使用该系统。这就是为什么可用性是导致用户采用系统的主要因素之一。构成可用性属性的有五个关键因素:
-
易学性:这个因素告诉我们用户第一次看到系统时执行任务有多容易。
-
效率:这个因素指定了用户完成主要任务的速度。
-
记忆性:这表示在长时间未使用系统后,记住执行主要任务的步骤有多容易。
-
错误:这规定了他们在系统中执行操作时遇到的错误数量,以及报告错误或恢复并继续完成任务有多容易。
-
满意度:这表明用户对整体设计的满意度。
在系统的最早设计决策中应仔细考虑可用性问题,以避免产品发布时最终用户的失望和挫败感。以下是一些关键技术的列表,以提高可用性:
-
考虑通过强制执行接受的 UI 设计标准来最大化易用性模式。
-
通过应用工作流简化用户交互和多步骤功能。
-
考虑使用异步调用以增加用户交互性,并执行后台任务,避免完整的后端调用。
互操作性
互操作性是一个质量属性,它评估了我们系统中组件在运行时成功合作执行任务以及高效交换信息的能力。
此外,互操作性是系统的一个属性,它负责系统的操作以及与其他系统的交互。这是一个不能忽视的属性。让我们了解一些关键技术来提高互操作性:
-
考虑使用连接器和 Web 服务来连接第三方系统并交换数据。
-
通过标准 Web 服务或 REST API 暴露功能,以与旧系统交换数据。
-
确保我们的架构设计允许组件之间有低耦合,以提高灵活性和可重用性。
在本节中,我们探讨了影响软件产品质量的运行时质量属性。这些属性应该在系统的实现和执行过程中被考虑和解决,以确保向我们的客户提供优质的产品。在下一节中,我们将探讨 ASP.NET Core 中的缓存机制。
网络应用程序中的缓存
缓存是一种技术,它允许我们在内存中存储频繁使用的数据。我们通常使用缓存来存储这些内容,然后在下一次请求相同内容时从内存中检索,而不是多次查询数据库以获取相同的内容。
缓存对于提高 ASP.NET Core 的性能和产品的整体用户体验至关重要。在 ASP.NET Core 中,有不同技术可以用于缓存数据。以下是这些技术的概述:
-
内存缓存:在这种技术中,服务器的内存用于存储数据。
-
分布式缓存:当我们的应用程序部署到 Azure 或托管在农场环境中时,使用此技术。缓存分布在参与此农场的服务器上。
让我们学习如何在 ASP.NET Core 中实现缓存。
在 ASP.NET Core 中实现缓存
在 ASP.NET Core 中,有两个内置的主要接口,您可以使用它们开始缓存关键任务的 内容:IMemoryCache 和 IDistributedCache:
-
IMemoryCache:这是一个允许我们应用本地内存缓存的接口。 -
IDistributedCache:这是一个提供一系列方法来在分布式环境中操作缓存的接口。
IMemoryCache 示例
以下代码演示了使用 IMemoryCache 来避免多次查询数据库获取相同内容的示例:
public class NewsService
{
private const string NewsCacheKey = "news-cache-key";
private readonly IMemoryCache _cache;
private readonly IDatabase _db;
public NewsService(IMemoryCache cache, IDatabase db)
{
_cache = cache;
_db = db;
}
public async Task<IEnumerable<NewsItem>> GetNewsList()
{
if (_cache.TryGet(NewsCacheKey, out IEnumerable<NewsItem> news))
{
return news;
}
news = await _db.getLatestNews<NewsItem>(...);
_cache.Set(NewsCacheKey, news, new MemoryCacheEntryOptions
{
//sliding expiration force the cache to become expired after 1 day.
SlidingExpiration = TimeSpan.FromDays(1)
});
return news;
}
}
在这个示例中,我们有一个 NewsService 类,其中有一个从数据库获取所有更新的方法。我们不想每次都查询数据库,而是想显示新数据。因此,我们决定使用 IMemoryCache 接口来利用其缓存机制。在 GetNewsList 方法中,如果可用,我们返回数据的缓存版本;否则,我们查询数据库然后将内容存储在缓存中。
IDistributedCache 示例
当应用程序托管在 Web 农场或云服务上时,应使用此接口。此接口不使用服务器的本地内存。此缓存由多个 Web 服务器共享。有各种选项来实现 IDistributedCache 接口:
-
我们可以使用 SQL Server 分布式缓存。此缓存将存储在 SQL 表中。为此选项,我们需要添加以下
Microsoft.Extensions.Caching.SqlServer。 -
我们可以使用
Microsoft.Extensions.Caching.StackExchangeRedis。
下面是一个示例,展示了如何使用 IDistributedCache 接口进行缓存:
public class NewsModel : PageModel
{
private readonly IDistributedCache _cache;
public NewsModel(IDistributedCache cache)
{
_cache = cache;
}
public string CachedNewsTime { get; set; }
public async Task OnGetAsync()
{
CachedNewsTime = "Cached Time Expired";
var encodedCachedNewsTime = await _cache.GetAsync("cachedNewsTime");
if (encodedCachedNewsTime != null)
{
CachedNewsTime = Encoding.UTF8.GetString (encodedCachedNewsTime);
}
}
public async Task<IActionResult> ResetCachedTime()
{
var currentTimeUTC = DateTime.UtcNow.ToString();
byte[] encodedCurrentNewsTime = Encoding.UTF8 .GetBytes(currentNewsTime);
var options = new DistributedCacheEntryOptions() .SetSlidingExpiration(TimeSpan.FromSeconds(60));
await _cache.SetAsync("cachedNewsTime", encodedCurrentNewsTime, options);
return RedirectToPage();
}
}
在这个示例中,我们创建了一个 Razor 页面来显示时间和两个异步方法:一个用于获取缓存的时钟,另一个用于重置缓存。
在 OnGetAsync 方法中,如果可用,我们获取缓存的时钟。ResetCachedTime 方法用于设置缓存对象并定义滑动过期时间为 60 秒,这意味着如果 60 秒内未使用,缓存将被清除。否则,当它被消耗时,缓存的时间范围将再延长 60 秒。
在前面的两个示例中,我们试图解释 IMemoryCache 和 IDistributedCache 之间的区别以及如何使用它们。您可以在许多 Microsoft 在线论坛中找到有关如何在 ASP.NET Core 中配置和实现缓存的逐步示例。
在下一节中,我们将探讨 ASP.NET Core 中的日志和跟踪机制。
日志和跟踪的统一解决方案
.NET 日志提供程序用于将事件消息记录下来,以跟踪应用程序的执行,并在集中位置报告所有代码错误或应用程序异常。跟踪用于跟踪和查看系统单个流程的诊断信息。
日志和跟踪对于 .NET 团队至关重要,因为每次应用程序失败时,我们都会请求信息以排查问题并解决它。日志和跟踪的统一解决方案将为您解答以下问题:
-
为什么系统未能完成该操作?
-
错误是在何时发生的?
-
代码中的哪个函数导致了异常?
-
函数之间交换的数据的状态是什么?
对于托管在本地环境中的传统解决方案,日志和跟踪由运行应用程序可执行文件的同一步骤执行。至于使用微服务模式构建的现代云应用程序,每个服务都在特定的进程中运行。在这种情况下,日志和跟踪由每个微服务进程生成。
以下图显示了 Microsoft 推荐的架构,用于使用 Azure 服务实现统一的日志和监控系统:

图 6.2:使用 Azure 服务的统一日志和监控系统
让我们了解前图中展示的主要组件:
-
事件中心:这是一个实时数据摄取服务,与所有其他 Azure 服务完全集成。它用于在一个集中式中心记录所有类型的事件。
-
Azure Monitor:此工具用于创建操作仪表板,以帮助通知 .NET 团队关于任何问题和关键故障。
-
应用程序洞察:这是 Azure Monitor 的一部分,用于监控实时 Azure 服务,检测性能异常,并诊断和跟踪故障。
-
逻辑应用:这是一个无服务器云服务,允许您使用用户友好且易于使用的可视化设计器安排和组织自动化工作流。
-
Blob Storage:这是一种用于云原生工作负载的云存储,用于存储非结构化数据和二进制文件。
-
Azure Data Lake Storage:这是一个提供大数据分析安全存储的云平台。它为开发人员和数据科学家提供了一组存储和分析大数据所需的功能。
-
Azure Sentinel:这是一个使用内置 AI 记录和分析安全信息,然后报告任何潜在威胁或异常行为的云平台。
-
Azure Stream Analytics:这是一个无服务器云引擎,用于收集和记录实时分析。
到目前为止,我们已经了解了主要组件。现在让我们了解图 6.2 中展示的日志和跟踪机制:
-
首先,我们的应用程序在 Azure 上托管,从用户界面操作和 Web API 调用中触发事件到 事件中心 和 Application Insights。
-
Application Insights 查询日志数据,追踪问题,并监控应用程序性能。
-
流分析 平台查询 事件中心 中的数据以触发 Logic Apps 工作流程并处理标记为关键指示器的事件消息。
-
然后,一个 Logic Apps 定时过程调用 REST 端点并向 .NET 团队发送警报。
-
Azure Sentinel 使用 Playbooks,这是一套由 Azure Logic Apps 驱动的流程,用于记录安全警报或事件。
-
所有日志随后将存储在 Blob 存储 和 数据湖存储 中,以便进行后续分析和故障排除。
在下一节中,我们将讨论在 Azure 中的高级部署步骤。
部署和监控规划
在本节中,我们将专注于将您的 ASP.NET 应用程序部署到 Azure App Service。这并不意味着其他传统部署选项不再有效,但我们认为,由于 Azure 提供的能力在传统网络托管中不存在,因此未来将现代应用程序托管在云中是趋势。包括 Azure 提供的能力在传统网络托管中不存在。
要将 ASP.NET Core 网络应用程序部署到 Azure,我们需要创建一个新的 Azure App Service 网络应用程序。在创建 App Service 之后,我们将能够使用 Git 或 Visual Studio 部署我们的应用程序。要创建 App Service,我们可以使用命令行脚本和 Azure Cloud Shell,或者您可以使用 Azure 门户 来创建和配置 App Service;两者都易于使用。
小贴士:
您可以参考 Microsoft 文档以获取创建 App Service 的详细步骤。请参阅 docs.microsoft.com/en-us/dotnet/architecture/devops-for-aspnet-developers/deploying-to-app-service?view=aspnetcore-5.0 中的 将应用程序部署到 App Service 部分。
创建 App Service 后,您可以使用 Visual Studio 发布应用程序。只需右键单击 Visual Studio 项目,然后发布即可。默认情况下,我们的应用程序将被部署到生产环境,我们可以在互联网上浏览它。
如果您想有一个预发布环境以便在将其移动到生产环境之前测试和批准更改,该怎么办? 在这种情况下,您可以使用 Azure 部署槽。您可以添加一个新的部署槽,这将允许您在两个部署槽之间交换应用程序资产以及配置设置,通常为预发布和生产。您可以参考 Microsoft 文档来创建预发布部署槽(类似的步骤可以用于创建生产槽):docs.microsoft.com/en-us/azure/app-service/deploy-staging-slots。
摘要
在本章中,我们探讨了影响我们架构整体质量的设计和运行时质量属性,以及这些属性如何影响我们的产品。理解和应用这些质量属性非常重要。这将使我们的产品具备修复和进化的能力。
接下来,我们学习了缓存对应用程序性能的影响以及如何使用 ASP.NET Core 接口来启用它。在本章的后面部分,我们讨论了现代应用程序中的日志记录和跟踪机制,然后我们探讨了 Azure App Service 的部署能力。
记住,作为解决方案架构师,我们的责任是从整体上获得令人满意的结果,这包括解决方案架构以及以正确的方式进行实施和部署——这正是我们在本章中试图涵盖的内容。
在下一章中,我们将深入探讨安全考虑因素,并突出一些关键技术来确保你的 ASP.NET 网络应用程序的安全。
第七章:第七章:保护 ASP.NET 网络应用程序
在上一章中,我们探讨了在设计实施解决方案架构时应考虑的架构考虑因素。为什么我们需要学习这些?因为创建一个创新且稳健的软件解决方案需要我们规划各个方面,并考虑不同的属性来平衡短期和长期的产品目标和优先级。关注属性的质量、日志记录和跟踪,以及适当的部署策略,将有助于你交付一个质量好、可扩展、可维护和安全的优质产品。
对于任何解决方案架构师来说,设计和构建一个炫酷的产品都是一件令人兴奋的事情;然而,如果我们不关注其中涉及的安全风险,这种成就可能会被破坏。安全是任何软件解决方案的组成部分,尤其是ASP.NET网络应用程序。从本质上讲,这些应用程序会暴露给大量用户,因此安全不再是奢侈品,而是一个必需品。
.NET Core框架提供了一套强大的功能和内置功能,如果我们正确实施和配置,可以保护我们的应用程序。然而,这还不够,因为我们仍然需要应用一系列安全措施并编写安全代码来保护我们的应用程序免受威胁和漏洞。
在本章中,我们将涵盖以下主题:
-
保护 ASP.NET Core 应用程序
-
Web 应用程序编程接口(API)安全建议
-
保护托管在 Azure 上的 Web 应用程序和 API
到本章结束时,我们将探讨一系列安全措施、技巧和窍门,帮助我们构建安全的 ASP.NET 网络应用程序。此外,我们将了解一些保护我们的 RESTful API(其中REST代表REpresentational State Transfer)的安全建议,以及一些在Azure上安全托管解决方案的提示。
最重要的是,本章为我们提供了一个确保解决方案安全的路线图。我们将深入了解如何将安全融入我们的解决方案架构,并看到创建安全软件最重要的因素是什么。
现在,让我们深入了解这些安全措施中的每一个。
介绍关键安全实践
在本节中,我们将探讨在构建我们的 ASP.NET 网络应用程序时需要考虑的关键安全措施。以下几节中包含一些C#代码示例,我们将使用这些示例来解释我们可能面临的各种安全漏洞。此代码语法基于ASP.NET Core和.NET 5,即使你有 ASP.NET Web Forms 应用程序,概念也是相同的。
以下是我们将在本节中学习的安全措施列表:
-
认证
-
授权
-
反跨站脚本(XSS)
-
跨站请求伪造(CSRF)
-
Cookie 窃取
-
过度发布
-
防止开放重定向攻击
-
阻止暴力破解攻击
-
文件上传保护
-
防止在 ADO.NET 和 Entity Framework(EF)中发生结构化查询语言(SQL)注入攻击
-
一般安全建议
身份验证
身份验证是验证试图访问应用程序的用户身份的过程。它从获取用户的凭据开始,然后将其与身份提供者(如Windows Active Directory)进行验证,该提供者可以是本地或作为Microsoft 365服务的一部分在云端。如果凭据的验证过程成功,则认为用户已通过身份验证。身份验证后,系统应开始授权过程,检查用户的访问级别并决定哪些数据和资源对该用户可访问。如果不了解用户是谁,则无法进行授权。
在 ASP.NET Core 中,有四种不同的身份验证模式,我们必须了解,如下所示:
identity模块。此模块将自动创建身份验证和授权 SQL 表,以及包括Register、Login、LogOut和RegisterConfirmation视图的 UI,这些视图将通过 scaffolding 功能添加到 Visual Studio 中。以下截图显示了在包管理器控制台应用迁移时将创建的 SQL 表:

图 7.1:ASP.NET 身份 SQL 表
通过使用此模式,未经身份验证的用户将被自动重定向到登录页面,在那里他们可以提供他们的登录凭据并将它们提交回服务器。如果身份提供者验证请求,ASP.NET 将颁发一个包含已验证用户 ID 令牌的 cookie,该令牌将被附加到每个请求的请求头中。这意味着所有后续请求都将自动使用存储在此 cookie 中的身份验证令牌进行身份验证。
这里是关于如何配置此身份验证模式的 Microsoft 参考:
)
appSettings.json文件;我们可以在注册应用程序后从 Azure Active Directory 获取这些设置:

图 7.2 – appsettings.json 文件中的配置
如前图所示,我们首先需要设置应用程序中使用的Domain名称。然后,我们需要设置从 Azure 获取的TenantId和ClientId。至于CallbackPath,这是我们希望在用户成功登录后重定向用户的统一资源定位符(URL)。
以下图表显示了使用 Microsoft 身份平台的认证过程:

图 7.3:使用 Microsoft 身份平台的认证过程
如您所见,未经认证的用户将被重定向到 Windows 登录页面,在那里他们被提示提供其凭据。如果凭据有效,则创建访问令牌。之后,用户将被重定向到登录页面或重定向到由身份提供者返回的 HTTP 响应中指定的 URL。
这里是关于如何配置 Microsoft 身份平台的一个 Microsoft 参考:
[docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-v2-aspnet-core-webapp](https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-v2-aspnet-core-webapp
)
-
Windows:这也被称为协商、Kerberos或新技术局域网管理器(NTLM)认证。这种认证模式最适合在同一个 Windows 域下运行的内部网络环境中的应用程序。它可以配置为在运行 Active Directory 域身份的内部网络上的Internet Information Services(IIS)或Kestrel托管的应用程序。此认证过程依赖于操作系统来获取用户的 ID 并确认认证。
这里是关于如何配置 Windows 认证的 Microsoft 参考:
[
docs.microsoft.com/en-us/aspnet/core/security/authentication/windowsauth?view=aspnetcore-5.0&tabs=visual-studio](https://docs.microsoft.com/en-us/aspnet/core/security/authentication/windowsauth?view=aspnetcore-5.0&tabs=visual-studio
)
- None:当我们选择此模式时,意味着不需要用户身份。这种模式用于两种情况——要么是我们的应用程序是公开的,任何人都可以访问它,要么是我们想构建自己的自定义认证模块。
在我们实施自定义认证过程时,以下是一些需要考虑的提示:
-
强制用户使用复杂密码,并在将其存储在用户表中之前对其进行散列。
-
永远不要在隐藏字段或任何状态管理对象中存储密码。
-
在将密码与请求头和正文一起提交到服务器之前,考虑使用客户端库对密码输入进行加密。在服务器端,当你收到密码时,你需要对其进行解密、散列,然后将其与数据库中散列的密码进行比较。如果它们相等,则认为用户已认证。
-
如果你正在使用会话,确保在注销时清除它们并修改会话 ID,在登录时生成一个新的会话 ID。
-
考虑实施双因素认证(2FA)。
-
永远不要授予任何用户对我们的 SQL 数据库的
db_owner访问权限,包括用于连接字符串的用户。
授权
授权是决定用户 ID 是否应该被授予访问应用程序中特定资源的权限的过程。通常,授权在认证之后立即开始,并且可以给用户授予不同类型的资源授权,如下所示:
-
URL 授权:这是为了选择性地授予用户和角色访问应用程序中特定 URL 的权限。
-
文件授权:这个过程用于保护应用程序的资产,防止未经授权的用户浏览目录。
-
UI 授权:这也被称为UI 剪裁。这个过程是为了选择性地允许或拒绝特定用户或角色访问页面的任意部分。如果用户没有访问权限,该部分将从页面上完全移除。
在控制器类或非匿名操作上应用授权 [Authorize] 属性是非常容易的。以下是一个例子:
[Authorize(Users = "john,tim")]
public IActionResult EditContent()
{
return View();
}
如果你允许匿名访问控制器类中的一个特定操作,该类顶部有 [Authorize] 属性,那么你需要在操作顶部使用 [AllowAnonymous]。你可以使用 [Authorize] 属性来授予角色访问权限,而不仅仅是用户。
抗 XSS
跨站脚本攻击(XSS)被认为是网络上的头号安全漏洞,不幸的是,许多网络开发者并不熟悉这种漏洞的风险。XSS 是一种注入攻击,攻击者试图在另一个用户的网络浏览器中执行恶意客户端脚本。
在 XSS 攻击方面有两种情况:第一种被称为被动注入,攻击者在输入字段中输入一个有漏洞的脚本,该脚本将被存储在数据库中,并在用户访问页面时显示。第二种被称为主动注入,用户将一个有漏洞的脚本输入到输入字段中,该脚本将立即在屏幕上显示。
让我们在接下来的几节中通过一些例子来探讨这两个场景。
被动注入
这种类型的 XSS 攻击发生在网页接受未经清洗的文本输入,这些输入可以稍后显示给访问此页面的受害者。假设我们有一个在线博客文章,允许用户发表评论并相互交流。
如果我们指定评论的输入字段接受文本而不进行验证或清洗,那么攻击者将在评论字段中注入一个客户端脚本,该脚本将在用户访问此博客文章时被触发。以下是一个包含恶意输入的评论示例:
This is a nice post<script>window.alert('This is an unsecure website')</script>
在这个例子中,注释中包含JavaScript代码,该代码将触发一个带有恶毒信息的警告。这个信息将被存储在注释表中,并且每次用户尝试访问页面时,脚本都会被触发,并将信息显示给最终用户,这非常令人烦恼。
攻击者可以注入 JavaScript 代码来操纵页面的HTML代码,例如在这个例子中:
This is a nice post<script src="img/badscript.js"></script>
在前面的例子中,你会注意到攻击者注入了一个客户端库,它可以操纵你页面的 HTML 代码并显示不同的内容。
激活注入
这种类型的 XSS 攻击发生在用户输入立即显示在网页上且未在服务器上保存的情况下。假设我们有一个网页,它正在从 URL 的查询字符串中读取元数据,并且当我们访问页面时显示欢迎信息。
在这种情况下,攻击者可以操纵查询字符串并传递以下输入脚本:
johnsmith\x3cscript\x3e%20alert(\x27XSS attack! weak security\x27)%20\x3c/script\x3e
这将在网页上显示XSS 攻击!弱安全警告信息。
让我们检查以下建议,以帮助保护你的应用程序免受 XSS 攻击:
-
不要信任任何用户输入,即使用户已经认证。你应该始终验证最终用户提供的输入。此外,你应该在将文本存储在数据库或显示在网页上之前对查询字符串进行编码和转义单引号。
-
确保 URL 查询字符串已编码,并且在使用之前始终验证查询字符串中的值。
-
在将未信任的内容存储在数据库之前,执行内容清理。HTML 清理是检查动态内容的过程,仅保留与白名单匹配的标签。
-
你应该始终使用
@Html.Raw来渲染未信任的内容。 -
你可以在将未信任的数据显示在 HTML 代码之前对其进行编码。这样,你可以确保没有人可以注入带有脚本代码的输入,因为编码机制会将
<转换为<,这将被视为普通文本。 -
确保设置
HttpOnly标志以保护我们的 cookie 不被客户端代码访问。
跨站请求伪造 (CSRF)
CSRF(也称为缩写XSRF,发音为sea-surf或c-surf)是一种攻击类型,由恶意网站执行,强制一个受信任但易受攻击的网站在用户仍然认证的情况下执行不希望的操作。
CSRF 攻击是可能的,因为浏览器请求包括封装认证令牌的 cookie。在这种情况下,攻击者利用认证 cookie 欺骗受信任的网站,通过使用受信任网站的认证 cookie 执行恶意请求,而受信任的网站无法区分合法请求和伪造请求。这种类型的攻击也被称为一键攻击或会话骑行。
执行 CSRF 攻击的最简单方法是通过发送数百万封声称用户赢得了一大笔钱或拉斯维加斯之旅的钓鱼邮件来吸引用户的注意力。通常,邮件中包含一个链接,会将我们带到恶意网站,并且为了领取奖品,恶意网站会要求我们点击一个花哨的按钮。
当然,用户会毫不犹豫地这样做,原因各不相同。其中一个原因是他们不知道点击按钮的风险或后果。一旦点击按钮,恶意网站就会在请求中附加一个认证 cookie,向受信任的网站发送恶意的请求。如果易受攻击的网站没有采取诸如验证传入请求(如本例中所示)之类的预防措施,那么攻击很不幸地将成功。以下是 CSRF 攻击步骤的示意图:

图 7.4:CSRF 攻击步骤
以下是一些应考虑以防止 CSRF 攻击的建议:
-
生成一个用户特定的 CSRF 令牌并将其存储在隐藏字段中。此令牌应与每个请求一起提交,并在所有
POST、PUT和DELETE请求上在服务器上进行验证。应在每次请求时重新生成令牌,以防止攻击者模拟此令牌并欺骗服务器端的验证过程。在 MVC 中,我们可以使用以下代码生成一个反伪造令牌:@using (Html.BeginForm("Create", "Product")) { @Html.AntiForgeryToken() //Here we put our form fields along with the submit button }这将输出以下 HTML 代码:
"__RequestVerificationToken" hidden field is holding the CSRF token. Here is an example, showing us how to force the post action in the controller to validate the token before executing the core functionality of the action:[HttpPost]
[ValidateAntiForgeryToken]
public async Task
Create (ProductViewModel newProduct) {
}
Notice the attribute on top of the action to validate the anti-forgery token. If the token is not valid, the request will be rejected/canceled. -
考虑检查传入请求的
referer头,它应引用受信任站点的同一域名。这将防止或取消来自不同域的请求。
Cookie 窃取
Cookie 是网站的一个基本组成部分,因为它们通常持有已登录用户的会话详情。Cookie是一个在客户端浏览器和服务器之间来回传输的对象。因此,而不是在每次请求时对用户进行身份验证,可以在 cookie 中存储认证令牌或声明,并在登录后使用它来识别用户。没有 cookie,用户需要在每次请求时重新登录。
如果你在应用程序中使用 cookie,确保 cookie 的安全性非常重要。Cookie 窃取(也称为会话劫持)是一种攻击类型,允许黑客窃取已登录用户的 cookie,然后冒充该用户并代表其发送请求。在这种情况下,服务器被欺骗,因为攻击者发送的请求看起来是真实的,因为它包含有效的认证 cookie。
为了防止 cookie 窃取,我们必须应用以下建议:
-
使用安全套接字层(SSL)证书,并仅允许HTTP 安全(HTTPS)请求来加密用户和服务器之间传递的所有请求。
-
考虑在
web.config文件中应用secure和HttpOnly标志来保护 cookie,并确保它仅通过 SSL 连接发送。 -
在登录后立即重新生成会话 ID。
-
考虑在注销时清除认证 cookie。
过度发布
ASP.NET 中的 模型绑定 处理传入请求与 .NET 应用程序模型之间的数据映射。这是一个强大的功能,它通过命名约定简化了用用户输入数据填充模型属性的过程。然而,这可能会通过允许攻击者填充表单中未呈现的一些模型属性而导致另一个安全漏洞。这种攻击被称为 过度发布 或 批量赋值。
让我们检查以下示例以了解过度发布漏洞。假设我们有一个用户模型,我们正在使用它在我们应用程序中注册新用户:
public class User
{
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public bool IsAdmin { get; set; }
}
这是一个相当简单的用户模型。你会注意到模型中有一个名为 IsAdmin 的属性——这个属性用于指定用户在整个应用程序上是否有管理访问级别。CSHTML 视图不应包含此属性,因为我们不希望最终用户决定他们的访问级别。视图应该看起来像这样:

图 7.5 – 用户注册示例表单
当表单提交时,它将生成以下 HTTP POST 请求:
Request URL:http://TheWebsiteUrl/register
Request Method:POST
Status Code:200 OK
firstname:John
lastname:miller
email:john@xxx.com
password:encryptedPassword
. . .
然而,当使用调试代理服务器工具时,我们可以修改这个 HTTP 请求并包含额外的值和属性。在这种情况下,攻击者会在 POST 请求中包含 IsAdmin:True。结果,用户将以管理员权限在系统中注册。
我们如何防止这种攻击? 好吧,有几个解决方案可以防止这种漏洞,例如以下几种:
-
在
public IActionResult Register(User model)中,我们可以使用public IActionResult Register(string firstName, string lastName, string email, string password),并在操作的实现中使用传递给操作参数的字段来填充模型。在这种情况下,任何由攻击者添加的额外属性都将被忽略。 -
RegisterUserViewModel。在这个新模型中,我们只添加了注册所需的属性,因此操作将变为public IActionResult Register(RegisterUserViewModel model)。我喜欢这个选项,并且通常将其作为常见做法。 -
在方法参数上使用
BindAttribute类,并且只包含(白名单)我们希望允许绑定到模型上的属性。因此,操作应该看起来像这样:public IActionResult Register(([Bind("FirstName,LastName,Email,Password") User model)]
作为一种良好的实践,我们不应该直接将数据库实体作为 MVC 视图和操作中的模型使用。
防止公开重定向攻击
让我们先了解什么是公开重定向攻击。如果你在 Web 应用程序中有逻辑将用户重定向到查询字符串或通过 HTTP 请求的参数中指定的 URL,这可能会被篡改以将用户重定向到恶意 URL,窃取他们的凭证。
假设攻击者发送了一封包含重定向链接的电子邮件,如下所示:
http://www.yourtrustedwebsite.com?ReturnUrl=www.fakedomain.com/login
通常,一些用户不会查看查询字符串,而其他人甚至不会检查 URL 的第一部分中的域名。当他们点击这个 URL 时,他们会被重定向到由恶意网站提供的登录页面。这个登录页面在外观和感觉上与受信任网站的原始登录页面非常相似。在这种情况下,用户会提供他们的凭据,假设他们正常登录。
然而,攻击者会窃取凭据并将它们重定向到受信任网站的原始登录页面。用户会感觉他们提供了错误的用户名或密码,因此他们会再次提供这些信息并继续他们在受信任网站上想要做的事情。
以这种方式,攻击者窃取了用户凭据,而受害者却从未察觉。这种攻击被称为开放重定向攻击。现在,让我们谈谈如何防止它。
当在你的 Web 应用程序中使用此类重定向逻辑时,将所有用户视为不可信。因此,我们需要确保只将重定向到我们应用程序内的本地 URL,或者使用 ASP.NET 中可用的新方法,名为LocalRedirect。这用于将重定向到应用程序本身内的本地 URL,这意味着在触发重定向之前会验证 URL,如果 URL 不是本地的,该方法将抛出异常。
此外,还有一个方法来验证一个 URL 是否是本地的——你可以使用Url.IsLocalUrl(..)。这个方法会返回一个布尔值来指示 URL 是否是本地的。
阻止暴力攻击
在密码学中,暴力攻击(也称为穷举搜索)涉及攻击者通过彻底尝试所有可能的字母、数字和符号组合来猜测密码,直到发现正确的组合。在许多情况下,攻击者会使用机器人工具执行自动攻击并预测密码。为了防止此类攻击,我们可以采取以下步骤:
-
在达到特定次数的失败登录尝试后锁定用户账户。
-
在登录页面上实施完全自动化的公钥图灵测试(CAPTCHA)。
-
考虑允许从特定的互联网协议(IP)地址登录,并限制其他所有 IP 地址的登录。
-
强制使用复杂的密码。
-
考虑启用双因素认证(2FA)。
-
阻止攻击者的 IP 地址,但这并不是一个保证的解决方案,因为攻击者可以更改他们进行攻击的 IP 地址。
-
考虑使用合适的用户名,并避免使用
admin、administrator或任何其他容易被猜到的用户名。
文件上传保护
文件上传允许用户在提交表单时上传文件。职业表单是文件上传用法的简单示例,其中用户在申请职位时需要附加简历。攻击者可以利用文件上传并尝试将恶意文件上传到服务器。以下是一些减少使用文件上传成功攻击可能性的安全步骤:
-
禁用存储上传文件的文件夹的执行权限。
-
确保只使用白名单来允许经过批准的文件扩展名。
-
启用客户端验证,在将文件上传到服务器之前检查文件扩展名。
-
检查上传文件的大小,并限制上传超过大小限制的大文件。
-
确保使用 .NET 服务器端代码检查上传文件的标题,以防止上传恶意文件。
-
对文件名进行编码,特别是如果您在 HTML 代码中显示文件名的话。
防止 ADO.NET 和 Entity Framework 中的 SQL 注入
SQL 注入 是一种漏洞,允许攻击者绕过应用程序中采取的安全措施,直接在应用程序的数据库中执行恶意 SQL 命令。
使用这些 SQL 命令,攻击者可以查询其他用户的数据。他们还可以修改数据,甚至删除某些表或整个数据库,这可能会给客户业务造成重大损失,尤其是如果没有适当的备份流程的话。
此外,他们可以将攻击升级以危害整个 SQL 服务器。SQL 注入攻击是我们可能面临的最危险的攻击之一,因为它影响整个数据库,以及可能托管在同一服务器上的所有数据库。让我们了解如何防止此类攻击,如下所述:
-
通过强制约束、验证数据的类型和格式以及执行清理来检查恶意输入数据。
-
考虑使用参数化 SQL 存储过程进行数据访问,并避免使用与内联 SQL 语句的文本连接。
-
永远不要将管理权限授予在数据访问层中使用的 SQL 用户——读取/写入权限就足够了。
-
避免泄露应用程序中可能发生的数据库错误详情。实际错误应正确记录在集中位置,并且应将最终用户重定向到没有技术详情的自定义错误页面。
-
在
web.config文件中加密 SQL 连接,以保护与数据库的连接安全。 -
SQL 注入漏洞适用于 NoSQL 数据库,如 Azure Cosmos DB 和 MongoDB,因此所有之前的建议也适用于这种情况。
一般安全建议
在前面的章节中,我们学习了主要的安全漏洞。在本节中,我们将强调一些安全建议,这些建议将提高解决方案的安全性,如下所述:
-
考虑启用审计跟踪、日志记录和跟踪来监控所有事件和传入请求。
-
通过安装 .NET 补丁始终升级您解决方案中使用的 .NET 版本,以从微软团队发布的安全增强功能中受益。
-
在将密码发送到服务器之前考虑加密,以避免嗅探攻击。
-
常见的安全步骤之一是启用以下响应头:
a.
Content-Security-Policy: 这允许我们指定可以加载到网站上的内容源白名单。它有助于防止 XSS,X-Content-Type-Options: 这有助于防止X-XSS-Protection: 这启用了 XSS 过滤器。 -
阻止
X-Frame-Options响应头。 -
通过删除以下响应头,防止泄露与托管服务器和 .NET 框架相关的敏感数据:
a.
Server: 这个头指定了 Web 服务器版本(IIS 版本)。b.
X-Powered-By: 这个头指示该网站由 ASP.NET 驱动。c.
X-AspNet-Version: 这个头指定了使用的 ASP.NET 版本。 -
避免使用已知存在漏洞的第三方组件和库。
-
考虑定期更新 NuGet 包,以利用最新的修复和增强功能。
-
如果您使用 IIS 托管您的应用程序,请确保加密连接字符串,因为它包含可以访问数据库的用户凭据。如果您使用 Azure App Service 托管您的应用程序,请考虑将连接字符串存储在 Azure 应用设置中,而不是
web.config文件中。
在本节中,我们探讨了一系列关键的安全实践,以帮助保护我们的 ASP.NET 网络应用程序免受恶意攻击。一旦应用了这些实践中的每一个,它将为应用程序添加一层安全防护。目标是强调在设计和构建健壮的 Web 解决方案时,解决方案架构师应关注的各个领域。
在下一节中,我们将学习如何通过一系列安全建议来确保 Web API 的安全。
Web API 安全建议
随着对构建现代网页和移动应用需求的不断增长,Web API 已成为赋予这些应用通信数据访问层功能的关键,同时也需要采取适当的措施来保护 Web API。除了我们在上一节中讨论的安全建议外,以下是一些确保您的 Web API 安全的基本技巧:
-
考虑使用最新的 传输层安全性(TLS)版本来加密应用程序和服务器之间的通信。
-
认证尝试消费 RESTful API 的用户。
-
通过启用审计日志、跟踪和日志记录来监控所有事件,表现得像跟踪狂。
-
考虑通过应用节流和配额来保护您的 API,例如限制特定时间内的消息数量。这对于根据可用容量控制服务器的带宽非常重要。
-
总是验证JavaScript 对象表示法(JSON)数据输入,以避免 SQL 注入。
-
在您托管 Web API 的服务器上启用适当的防火墙配置。
-
考虑使用 API 网关,这是一个位于客户端应用程序和 RESTful API 之间的中间件层。这可以帮助您保护、控制和监控 RESTful API 的流量。
-
防止分布式拒绝服务攻击(也称为DDoS攻击),这种攻击通过并发连接的洪水来发送大量无用的请求,从而耗尽托管服务器的内存和容量。您可以通过启用基于并发请求数量的动态 IP 限制扩展来防止 IIS 中的 DDoS 攻击,该扩展可以阻止来自某些 IP 地址的传入请求。如果应用程序托管在 Azure 上,则我们可以启用Azure DDoS 保护。
-
考虑在每次请求中强制执行时间戳,将其添加到请求头中。服务器应验证此时间戳,以确保只接受在特定时间段内的请求。这种方法可以帮助您保护 Web API 免受暴力攻击(在阻止暴力攻击部分中解释)和重放攻击,这些攻击允许攻击者恶意完成重复请求。
在本节中,我们讨论了一系列应应用于确保 ASP.NET Web API 安全的建议。
保护托管在 Azure 上的 Web 应用程序和 API
在本节中,我们将强调如果您在 Azure 上托管 Web 应用程序或 Web API,应牢记的一些安全建议,如下所述:
-
考虑启用Azure Defender以保护您的应用程序服务。
-
总是运行 Azure Defender 中可用的集成漏洞扫描程序,以扩展 SQL 服务器及其存储数据库的保护。
-
您可以通过使用受支持平台、框架和协议的最新版本来保持应用程序服务最新。
-
禁用对 blob 存储的匿名访问以保护上传的文件。如果需要,您可以启用对特定文件夹的匿名访问。
-
强制使用SSL/TLS协议以提供安全连接。
-
总是使用安全文件传输协议(FTPS)而不是常规的FTP来部署您的文件,如果您不使用 FTP,请禁用 FTP 协议。
-
考虑使用环境变量来存储您的数据库凭据、API 令牌以及任何应用程序设置。
-
考虑使用云Windows 应用程序防火墙(WAF),这可以帮助保护您的 Web 应用程序免受恶意攻击和常见的 Web 漏洞,例如 SQL 注入和 XSS。
摘要
在本章中,我们了解到安全性是 Web 解决方案的一个基本组成部分。我们概述了基本的安全措施和技术,以帮助理解可能的安全漏洞,这将使我们能够保护 ASP.NET Web 应用程序免受恶意攻击。
此外,我们强调了确保我们的 RESTful API 的一些关键指南。在本章的后面部分,我们探讨了确保可以在 Azure 上托管的应用的一些技巧。这些安全实践使我们能够构建既强大又安全的 ASP.NET 应用程序。
除了本章中分享的建议外,我强烈建议您通过阅读微软.NET 团队分享的在线官方文档来不断更新您对 ASP.NET 安全特性的知识。以下是文档的链接:docs.microsoft.com/en-us/aspnet/core/security/?view=aspnetcore-5.0。
在下一章中,我们将探讨在发布解决方案之前可能需要进行的各种测试类型。
第八章:第八章:解决方案架构中的测试
在上一章中,我们学习了如何确保 ASP.NET 网络解决方案的安全。我们还强调了保护我们的网络 应用程序编程接口(API)的一些关键安全建议,以及当在 Azure 上托管时的安全最佳实践。
在本章中,我们将熟悉你需要了解的最常见的测试类型及其使用时机。
在本章中,我们将涵盖以下主题:
-
突出关键测试原则
-
了解主要的软件测试类型
-
探索 Azure 中的测试
到本章结束时,你将了解我们可以应用于测试我们的软件解决方案的各种软件测试类型,目的是找到错误并修复它们。我们还将学习如何检查软件是否正常工作以及它是否满足项目早期阶段定义的要求。我们还将探索 Azure DevOps 提供的测试机制。
在下一节中,让我们来看看软件测试的关键原则。
突出关键测试原则
进行软件测试的主要目标是消除可能的错误,并在许多方面提高软件的整体质量,例如性能、用户体验(UX)和安全。
但在开始任何测试活动之前,必须有一些指南或原则来确保这些活动的结果与测试的主要目标一致。在本节中,我们将强调我们在软件解决方案中需要考虑的一些关键软件测试原则,如下所述:
-
所有测试用例都应根据客户需求准备;否则,我们将针对错误的要求进行测试。系统中的每个功能或功能都应该使用一个或多个测试用例进行测试。
-
一些类型的软件测试,如 性能测试 和 验收测试,应由 领域专家(SMEs)如 质量保证(QA)工程师或高级开发者执行。
-
计划首先测试基本功能,然后扩展到测试高级功能。
-
建议在项目的早期阶段开始测试,因为在这种情况下,修复缺陷的成本远低于在项目后期阶段进行测试。
-
缺陷聚类基于 帕累托 原则,该原则指出,80% 的缺陷是由 20% 的系统功能引起的。这意味着在测试过程中,检测到的大量缺陷都与少数功能相关。
-
不建议反复执行相同的测试用例,因为经过一段时间后,我们不会找到任何新的缺陷。最佳实践是调整测试用例,目的是找到新的缺陷。
-
测试是上下文相关的,这意味着我们需要根据我们测试的系统上下文应用特定的方法和技术。例如,测试内容管理系统(CMS)与测试 iOS 电子商务应用不同。
让我们开始探索各种测试类型。
探索软件测试的主要类型
软件项目失败的主要原因之一是产品质量不足。软件测试是项目生命周期的一个组成部分,有助于确保产品无错误/缺陷,并且同样验证实现的功能以确保它们与客户定义的要求相匹配。软件测试主要有两大类,如下所述:
-
功能测试:这是用来验证系统的每个功能和特性,以验证所有功能。
-
非功能测试:这是用来验证系统的非功能性方面,如性能、可用性和合规性。
下面是一个展示我们将在本章中讨论的不同类型测试的图表:

图 8.1:测试类型
我们将在接下来的章节中查看前面图中显示的所有不同类型的测试。
单元测试
单元测试是一种测试类型,用于测试系统的每个单独的功能或模块。通常,它是由正在开发产品的.NET 开发者执行的,因为它需要一些编码技能。这就是为什么它被认为是一种低级测试类型,因为它只针对代码的行为。
下面是一个展示单元测试级别作为整个测试生命周期组成部分的图表:

图 8.2:测试生命周期中的单元测试级别
在前面的图中,单元测试代表在开始任何其他测试活动之前应该进行的第一个测试类型,因为随着测试级别的提高,修复缺陷的成本也会增加。
下面是单元测试的一些好处:
-
单元测试使我们能够在开发周期的早期阶段修复缺陷。这将节省在验收测试阶段修复相同缺陷的时间和成本。
-
它有助于记录源代码。
-
它允许开发者重构代码并重用现有函数来消除 API 中的任何重复。
-
如果我们对 API 进行更改,单元测试对于测试依赖项至关重要。
-
它有助于降低代码复杂性。
有关自动化单元测试的更多详细信息,请参阅微软推荐的测试工具列表:docs.microsoft.com/en-us/dotnet/core/testing/#testing-tools.
)
集成测试
集成测试旨在测试解决方案中的两个或多个模块,以验证它们是否能够良好地协同工作。例如,它可以涉及测试我们正在构建的系统与Azure Active Directory之间的集成行为,以验证认证机制。
这种类型测试的另一个例子是我们需要验证我们的系统与数据库层之间的交互。集成测试应在完成我们正在进行的测试的两个模块的开发后进行。
在以下图中,我们展示了集成测试应仅针对模块 A和模块 B之间的集成部分:

图 8.3:两个模块的集成测试
这里有一些集成测试的好处:
-
集成测试有助于确保集成模块按预期正常工作。
-
它允许模拟系统内各个模块之间的转换。
-
它还有助于检测模块交互中可能出现的错误。
回归测试
测试我们对系统进行的任何新更改是很正常的,例如修改现有功能或添加新功能。然而,这还不够,因为在大多数情况下,我们更改或添加的代码将对其他功能产生直接或间接的影响,也许还会影响系统中的其他功能。这就是为什么我们需要进行回归测试,以确保新代码没有引起任何新的缺陷。
在以下图中,我们展示了回归测试的三个主要步骤:

图 8.4:回归测试的主要步骤
这里有一些回归测试的好处:
-
回归测试确保在模块或代码发生更改的情况下,现有功能保持不变。
-
自动回归测试有助于实现持续集成(CI),这可以节省时间和成本。
-
它允许检测由系统环境变化引起的缺陷。
-
它增加了客户信任和满意度,这可能导致业务扩张。
烟雾测试
烟雾测试是一种在管道行业中采用的技术,他们通常使用白烟来识别管道中的任何泄漏。
今天,烟雾测试的概念在软件开发中被用来验证构建的基本功能。如果测试失败,构建被认为是不稳定的,系统尚未准备好执行任何其他类型的测试活动。
以下图展示了烟雾测试的主要阶段:

图 8.5:烟雾测试的生命周期
在前面的图中,我们可以看到测试过程是从创建一个带有版本号的新构建开始的。之后,我们需要优先考虑测试用例,并决定要确切测试什么,以便在功能测试之前认证新的构建。如果烟雾测试失败,那么我们需要修复缺陷,并通过创建一个新的构建重新开始。
这里是烟雾测试的一些好处:
-
它有助于在开始任何其他类型的测试之前,在早期阶段检测到阻止问题。
-
它通过检测如果他们想要运行功能测试可能需要更长时间才能检测到的缺陷,从而提高了 QA 团队的效率。
端到端测试
端到端(E2E)测试被认为是应用程序的全面测试。通常,测试整个系统的功能很方便;进行此类测试时,重要的是要复制生产环境,并且测试场景应该模仿用户行为。此类测试的主要目标是确保不同的用户流程在没有错误且符合要求的情况下正常工作。
在下面的图中,我们展示了端到端测试过程的三个主要步骤:

图 8.6:端到端测试的三个主要步骤
在前面的图中,用户功能代表在系统特定功能中执行的操作,条件代表可以应用于每个用户功能的各种输入数据和序列。至于测试用例,这些是基于前两个动作创建的——即用户功能以及条件。
这里是端到端测试的一些主要好处:
-
它有助于确保系统的完全就绪和健康。
-
它允许我们从用户的角度全面测试整个系统。
-
它有助于测试最终用户可以应用的现实场景。
用户界面测试
术语用户界面(UI)本身就说明了问题。UI 测试是为了测试应用程序的图形用户界面(GUI),目的是确保应用程序的 UI 按照要求开发,并且用户友好。
在下面的图中,我们可以看到业务层和数据层可以通过单元测试进行测试。至于 UI,唯一的测试方式是通过 UI 测试:

图 8.7:UI 测试
这里是 UI 测试的一些主要好处:
-
它有助于检查 UI 元素的排列,以及检查字体样式、颜色和显示文本的清晰度。
-
它允许我们检查产品是否在所有应支持的所有设备和屏幕上正确渲染。
-
它有助于检查错误信息和警告信息。
接受测试
验收测试(也称为用户验收测试,或UAT)被认为是测试的最后阶段,通常由客户的关键用户执行,以验证所有业务需求都已开发,并且系统按预期正常高效地运行。通常,验收测试是基于在项目分析阶段准备的用户案例生成的测试用例进行的。
在下面的图中,我们展示了 UAT 是迁移到生产环境前的最后一个测试阶段:

图 8.8:项目生命周期中的 UAT
下面是 UAT 的一些好处:
-
它有助于验证在项目开始时定义的所有业务需求都正确实施且运行正常,没有任何错误。
-
它允许在开发过程中而不是在生产环境中修复检测到的缺陷,这成本较低,尤其是在在线支付解决方案的情况下。
-
它有助于在上线阶段之前增加用户对新系统的信任。
性能测试
性能测试是一种非功能性测试,通常用于检查系统是否按照客户定义的性能要求和标准正常工作。
在执行性能测试时,考虑以下四个主要元素:
-
瓶颈是导致系统崩溃的主要问题。
-
加载页面或表单所需的加载时间。
-
触发动作或完成流程所需的响应时间。
-
可扩展性是指系统在不崩溃的情况下处理大量请求的能力。
以下图显示了执行性能测试的四个主要元素:

图 8.9:性能测试元素
下面是性能测试的一些好处:
-
它有助于衡量系统的响应时间、准确性和稳定性。
-
它允许检测到减少应用程序响应时间或整体硬件使用率的问题。
-
它有助于提高页面加载时间,并增加用户满意度。
压力测试
压力测试是一种非功能性测试,用于验证系统的稳定性和可靠性。压力测试的主要目标是测量系统在超出正常操作情况下的极端高负载请求下的强度和错误处理能力。其目的是了解系统在这种高负载下的行为。
以下图描述了压力测试的步骤:

图 8.10:压力测试主要步骤
初始阶段,压力测试过程从规划和决定测试用例开始。之后,我们应该创建脚本并在自动化过程中执行它们。应仔细分析压力测试的结果,以确定任何问题的根本原因。最后,我们需要通过优化代码来修复问题,然后重新运行整个压力测试过程,直到我们得到一个稳定的构建。
这里有一些压力测试的好处:
-
这允许我们检查和处理可能出现的错误消息。
-
在任何由大量请求引起的故障发生之前,这有助于检查数据是否正确保存。
合规性测试
合规性测试(也称为一致性测试)是一种审计测试技术,通常在决定系统是否准备好发布之前执行,以验证产品是否满足一系列外部和内部标准。
内部标准通常由组织设定。例如,一个网站应该为各种设备和屏幕设计,因此它应该提供响应式用户界面。
至于外部标准,这些是由全球联盟或专注于此类测试的第三方组织设定的规定。外部标准的一个例子是通用数据保护条例(GDPR)或网络内容可访问性指南(WCAG)。
下图显示了合规性测试通常评估的主要系统属性:

图 8.11:合规性测试评估的系统属性
如前图所示,每个属性都对系统的整体合规性做出了贡献。因此,让我们了解以下每个属性:
-
鲁棒性:这显示了系统在受到干扰时正常工作的能力。
-
性能:这代表系统完成单个任务所需的时间。合规性测试应衡量系统主要功能的表现,并基于预定义的测试标准证明它们表现良好。
-
互操作性:这显示了系统与其他第三方系统交换信息的能力。此外,它还显示了系统中的不同功能如何相互作用以完成一个过程。
-
功能:这评估了系统提供的接口和功能,并确认项目早期阶段定义的要求是否得到满足。
-
系统行为:这评估了系统与其托管环境的行为。它还评估了系统在执行之前定义的每个用户故事之后的行为。
灾难恢复测试
对于企业解决方案和关键任务系统,应考虑灾难恢复计划(DRP)。它包括一系列详细的指南和策略,应实施以处理可能干扰系统正常运行的意外事件。一个好的 DRP 应使我们能够快速从网络攻击、停电、硬件故障或其他任何事件中恢复过来。它应确保业务流程的连续性,并尽可能减少损害。
DR 测试是通过评估过程中的每个步骤来验证 DRP 的过程,以确保在发生事件时能够按预期工作。
到目前为止,我们已经探讨了主要的测试类型和技术,例如单元测试、冒烟测试、性能测试和验收测试。了解每种测试类型及其何时使用对于交付高质量的软件产品至关重要。我们应该确保产品符合标准和要求,从编码到产品整体的企业功能。在功能测试和非功能测试之间应用不同的测试类型将提高质量,以实现卓越的结果。
在下一节中,我们将探讨 Azure 中测试计划的功能。
探索 Azure 中的测试
手动测试可以是提供出色 UX 和在生产前验证产品的一个关键测试技术。Azure 测试计划与Visual Studio 2019一起提供了我们管理测试工作所需的功能,从手动和探索性测试到负载和压力测试。
起始点是创建一个由配置、测试套件和测试用例组成的测试计划,这些测试用例可以分解为共享的测试步骤,并使用允许我们重复测试但使用不同输入数据的参数。
使用以下链接登录 Azure DevOps:azure.microsoft.com/en-us/services/devops/。
登录成功后,你可以在左侧菜单中看到测试计划,如下面的截图所示:

图 8.12:Azure DevOps 中的测试计划
创建测试计划后,我们需要设置测试的配置,例如,如果我们正在测试 Web 应用程序,我们可以指定操作系统和浏览器配置。测试配置可以分配给整个测试计划或单个测试套件,甚至测试用例。如果我们将配置分配给测试计划,这将确保所有创建的测试用例都自动分配到这些配置。
当你点击测试计划时,将打开一个滑动子菜单,显示更多功能,例如我们可以创建新的测试计划、设置参数和修改配置,如下面的截图所示:

图 8.13:测试计划下的配置
在设置测试配置后,我们现在可以开始创建测试套件,即测试用例的集合。
有三种不同类型的测试套件,如下所述:
-
静态测试套件:这是一个逻辑容器,我们可以添加任何我们喜欢的测试用例。
-
基于需求的测试套件:这是我们将测试用例关联到工作项以定义其验收标准的地方。
-
基于查询的测试套件:这是我们创建工作项查询以选择要包含哪些测试用例的地方。任何符合查询标准的测试用例都将自动添加到测试套件中。
在我们定义测试套件后,我们需要开始创建测试用例并将其分配给测试团队。创建测试用例是一个非常直接的过程。主要元素是在任何预期结果中执行的步骤。经常重复的步骤可以提取为共享步骤以简化测试维护。在准备测试用例后,我们就可以开始手动进行测试运行了。请注意,从运行页面,我们可以查看所有之前的测试运行及其结果。
到目前为止,我们已经学习了在 Azure 中进行手动测试的相关知识,它有其优势。但是,当我们开发更多功能并且源代码的规模增长时,手动测试所有功能可能会变得重复且耗时。因此,Azure 为我们提供了一个机制来自动化我们的测试,以消除手动测试的负担,并允许质量保证工程师专注于提供更好的质量和改进的用户体验(UX)。
使用 Azure DevOps,我们可以通过 Azure 管道来自动化从 Azure 测试计划中的测试。我们可以使用 Azure 管道自动化许多类型的测试,例如单元测试、安全测试和代码覆盖率测试,该测试计算单元测试覆盖的代码百分比。
在使用 Azure 测试计划进行测试时,以下是一些关键建议:
-
确保测试是有目的的,并对产品有积极的影响,并尽量不为了测试而测试。
-
保持测试简单、专注且简短。测试应该快速运行,尤其是如果它们是在产品的构建或发布上触发的。
摘要
在本章中,我们探讨了概述进行适当测试所需的基本指南的一些关键原则。我们还了解了作为解决方案架构师我们必须知道的必要测试类型。了解每种测试类型将帮助我们决定应该应用哪些功能和非功能测试,以确保高质量的软件产品并交付满足要求的产品。在本章的最后部分,我们探讨了 Azure DevOps 中测试计划的功能以及关键优势。
在下一章中,我们将深入探讨使用 ASP.NET Core 和 Microsoft Azure 架构现代网络应用程序。
第三部分:使用 DevOps 解决方案构建现代网络解决方案
在本节中,我们将概述现代网络解决方案的特点,并学习如何在传统网络应用和单页应用(SPAs)之间进行选择。之后,我们将探讨流行 SPA 框架中的项目结构。然后,我们将探索在 Azure 中的托管选项,并提供高级推荐。
在本节的后面部分,我们将了解如何利用 Azure DevOps 通过使用现代软件开发实践,如 Azure Artifacts 和 CI/CD 实践,来构建、测试和部署我们的应用程序。
本节包括以下章节:
-
第九章,使用 ASP.NET Core 和 Azure 构建现代网络解决方案
-
第十章,设计和实现 Microsoft DevOps 解决方案
第九章:第九章:使用 ASP.NET Core 和 Azure 架构现代网络解决方案
使用 ASP.NET Core 构建丰富和动态的网络解决方案,并在 Azure 中托管,比传统的网络开发实践提供了更大的价值。
本章为我们提供了如何使用现代 .NET 技术和云托管场景架构网络解决方案的基础理解。
在本章中,我们将涵盖以下主题:
-
现代网络解决方案特性的概述
-
学习如何在传统网络应用和单页应用(SPAs)之间进行选择
-
理解流行 SPA 框架中的项目结构
-
在 Azure 中探索托管选项,并提供高级推荐
到本章结束时,我们将学会如何使用 ASP.NET Core 架构跨平台现代网络解决方案,以利用其改进的性能,这是该框架最明显的优势之一,以及其基于云的开发支持。
此外,我们还将了解如何在传统网络应用和 SPAs 之间进行选择,以及 Angular、React 和 Vue 的快速比较。我们还将学习如何为我们的解决方案选择最佳的 Azure 托管方法。
探索现代网络解决方案的特性
不论是客户所在的行业还是业务,随着时间推移,现代网络解决方案的用户期望都在不断增加。最终用户期望使用响应式网络解决方案,可以从不同设备上访问,这些设备具有各种屏幕尺寸。
此外,网络解决方案必须安全、灵活和可扩展,以便在短时间内以较少的努力添加新功能。现代网络解决方案预计将易于使用,并具有良好开发的用户体验。这为我们客户提供独特的竞争优势,以保留客户并使自身与竞争对手区分开来。在本节中,我们将强调现代网络解决方案的主要特性。
可扩展和云托管解决方案
在当前的现代时代,云采用是加速数字化转型的一种方式,原因有很多,例如根据不断出现的需求自动扩展或缩减资源分配的能力。此外,云托管提供了各种工具来自动化业务操作,以及强大的安全措施,确保保护与网络解决方案相关的个人数据和客户信息。
ASP.NET Core 是最佳选择,完美处理这些因素。它是一个针对云解决方案优化的跨平台网络框架。它以性能和可扩展性为设计理念,这意味着更少的 RAM 和 CPU 消耗,这将为我们节省基础设施和托管成本。
模块化和松散耦合的架构
模块化架构是一种设计方法,它由组装多个模块来构建系统。模块化概念的主要好处是灵活性,这使我们能够轻松地将额外功能添加到系统中,以及松散耦合的模块,这有助于降低维护成本。
使用 ASP.NET Core 在现代网络解决方案中实现模块化概念是值得的。它是一个开源框架,由不同的 NuGet 包开发而成。这意味着我们的网络解决方案只会编译解决方案中真正需要的包,而不会包含从未使用过的额外库,就像 .NET 框架那样。通过消除解决方案中不需要的库,我们在某种程度上减少了安全漏洞。
ASP.NET Core 设计用于允许 依赖注入。这是一种设计技术,通过使用接口或通过将低级类的具体实现注入到高级类中来减少组件或类之间的依赖问题。
查阅 Microsoft 文档以获取有关依赖注入的更多信息:docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-5.0.
)
自动化测试
测试 是验证我们正在开发的产品的一个关键阶段。虽然由于许多原因,如探索性测试和视觉测试,手动测试仍然很重要,但自动化测试提供了巨大的好处,如节省成本、提高生产力、高质量的产品和更好的性能。
ASP.NET Core 使我们能够轻松测试我们正在开发的系统,因为该框架灵活且可靠,允许快速自动化测试。它提供了为 模型-视图-控制器(MVC)应用程序以及现代网络解决方案所必需的 Web API 编写单元测试的能力。它与 Azure 无缝集成,使我们能够完全访问 DevOps 测试工具的最新功能,这对产品和开发团队来说非常有价值。
传统和单页应用程序支持
在网络世界中,单页应用程序(SPAs)很流行,但这并不意味着每个网络解决方案都应该使用这种技术。基于 MVC 框架的传统网络解决方案仍然有需求,并且在许多情况下可以使用。基于 ASP.NET MVC 的传统网络解决方案依赖于服务器来处理请求并渲染视图,而 SPAs 则严重依赖于 Web API 来获取渲染组件所需的数据。
现在,许多网络解决方案都涉及传统网络应用和单页应用的行为。ASP.NET 支持在同一 Visual Studio 项目中拥有 MVC 网络应用和 Web API。此外,它允许使用任何现代前端框架构建 Web 应用,例如 Angular、React 和 Vue,以及后端 Web API。
快速部署
容易将新更改部署到网络解决方案是至关重要的。使用 Azure DevOps 管道,我们可以将 ASP.NET Core 解决方案的部署过程自动化,作为 持续集成 和 持续交付 管道的一部分。Microsoft Azure 还与 Git 仓库集成,允许自动部署对特定 Git 分支或标签所做的更改。
此外,我们可以使用 GitHub 提供的工具和实践,这些工具与 Azure 完全集成,以更快地交付我们的产品。通过 GitHub Actions,这些类似于 Azure 管道,我们可以使用由步骤和作业组成的流程来自动化软件开发过程。这些工作流程可以帮助我们使用自动化工作流程在 GitHub 上构建、测试、打包、发布和部署任何项目。
想了解更多关于 Azure 可用的 GitHub 动作的信息,请查看以下参考资料:
[docs.microsoft.com/en-us/azure/developer/github/github-actions](https://docs.microsoft.com/en-us/azure/developer/github/github-actions
)
使用 Blazor 的渐进式 Web 应用
Blazor 是一个提供使用 C# 而不是 JavaScript 构建交互式 Web 应用的强大功能的 Web 框架。它依赖于开放网络标准,无需安装任何插件。它可以用来构建单页应用以及 渐进式 Web 应用(PWAs)。
PWAs 是利用浏览器最新技术的网络应用,提供与移动应用相似的用户体验。它们是移动和 Web 开发中的一个强大趋势。Blazor WebAssembly 是用于构建 PWA 应用的客户端框架。以下是这种技术的优势:
-
它允许无缝离线操作,并且应用可以立即加载。稍后,它可以与服务器同步以发送数据。
-
开发成本较低,因为我们不需要为多个设备构建不同的版本。
-
它为用户提供与移动应用类似的 UI/UX。
-
服务器可以推送通知,就像原生应用一样,即使用户没有在使用应用。
-
无需将应用发布到商店进行分发和发现。应用可以通过链接或快捷链接访问,这些链接可以放置在开始菜单或主屏幕上。
在本节中,我们强调了现代网络解决方案的一些关键特性。在下一节中,我们将学习如何在传统网络应用和单页应用之间进行选择。
在传统网络应用和单页应用之间进行选择
到目前为止,我们已经看到了构建 Web 应用程序的两种方法。一种方法是传统的服务器端方法,其中所有应用程序逻辑都在服务器端提供。另一种方法是现代方法,由单页应用程序(SPAs)代表,其中所有用户交互都由浏览器通过客户端框架处理,该框架通过消耗 Web API 与 Web 服务器通信。还可以通过将两种方法结合在一个解决方案中来实现混合解决方案。
以下图表展示了两种方法。我们可以看到,在单页应用程序中,我们有多模板将在一个单页面上使用客户端框架渲染;此外,这种方法中也没有全页刷新。而在传统 Web 应用程序中,我们可以看到多个页面,在从一个页面导航到另一个页面时将强制进行全页刷新:

图 9.1:单页应用程序与传统 Web 应用程序的比较
每当我们想要架构和开发一个新的 Web 解决方案时,通常会想到一个问题,我们应该采用哪种方法——传统还是单页? 让我们学习如何在这两种方法之间进行选择。
选择传统 Web 应用程序
在我们开始讨论选择传统 Web 应用程序的关键原因之前,让我们了解这种方法中页面生命周期的概念。以下是展示传统 Web 应用程序请求生命周期的图表:

图 9.2:传统页面生命周期
在前面的图表中,我们可以看到用户发起的初始请求是为了浏览一个页面。这个请求被服务器接收,服务器将处理它并返回一个 HTML 页面作为响应,这被视为全页刷新。当我们向服务器提交表单时,行为也是一样的。
这种方法的一个好例子是经典的 ASP.NET MVC 应用程序,它没有使用任何 JavaScript 框架通过AJAX请求来渲染视图。
现在,让我们了解何时应该选择传统 Web 应用程序方法:
-
如果应用程序的客户端需求很简单,那么传统方法是一个很好的选择。例如,大多数CMS网站都是供用户阅读内容使用的,对客户端功能的需求很小。在这种情况下,应该采用传统方法来开发这样的应用程序,其中实际逻辑在服务器上执行,并将响应作为 HTML 返回给用户的浏览器。检查一下纽约时报网站——你会注意到,当你从一个文章导航到另一个文章时,浏览器中的 URL 会改变,这是该网站使用传统方法构建的标志。
-
如果我们的团队尚未采用 JavaScript 和著名的 frontend 框架,如 Angular、React 和 Vue,并且在我们开始项目之前没有足够的时间对他们进行培训。
-
如果客户端请求是不支持 JavaScript 的 Web 应用,在这种情况下,浏览器中默认将禁用所有 JavaScript 库。在大多数情况下,这是在内部网络 Web 应用中请求的,而不是在线网站。在线网站上,必须启用 JavaScript,否则我们无法从各种设备打开网站。
-
如果 SEO 是项目中改善内容营销和吸引更多潜在客户和读者到网站的关键问题。可以配置 SPA 来提高应用程序的 SEO 排名。然而,这种排名在具有适当 URL 的多个页面中显示更好的结果。
这些是引导我们选择传统方法的主要关键因素。在下一节中,我们将学习何时选择 SPA 方法。
选择单页应用程序
SPA 是一个单页应用程序,它使用 JavaScript 在单页上渲染多个视图。在下面的图中,我们将探索 SPA 中的请求生命周期:

图 9.3:单页应用程序生命周期
在前面的图中,我们可以看到初始请求是由最终用户首次打开 SPA 应用触发的。服务器将通过返回主页的完整 HTML 来回答。此外,用户将触发另一个功能,例如更新数据库中的数据并刷新视图。
这将通过大多数著名前端框架所使用的 AJAX 技术来实现。AJAX 调用将消耗一个网络服务或网络 API,并返回一个 JSON 对象,然后它只刷新视图而不进行整个页面的刷新。这创造了一个流畅的用户体验,使用户感觉就像在使用原生应用一样。
现在,让我们了解何时应该选择 SPA 方法:
-
如果需要提供用户在网络或互联网未连接时能够离线工作的能力。SPA 方法将使用户能够在应用程序再次连接到网络时同步其数据。
-
如果减少带宽消耗是至关重要的。众所周知,SPA 应用在初始请求时只加载一次资源,并且它们比传统 Web 应用消耗更少的带宽,因为它们不会在每次请求时加载和传输完整的 HTML 页面。
-
如果响应时间和用户体验对客户至关重要。众所周知,SPAs 中的请求响应时间远远优于传统应用程序。此外,无缝且丰富的用户体验可以显著影响我们客户的业务,并最终增加潜在客户和销售额。
-
如果对于 Web 应用来说 SEO 不是很重要,并且如果你的团队熟悉 JavaScript、TypeScript 以及任何前端框架,如 Angular、React、Vue 或 Blazor WebAssembly。
在本节中,我们学习了如何在传统 Web 应用和 SPA Web 应用之间进行选择。我们还解释了两种方法请求的生命周期。在下一节中,我们将快速概述一些常见的 SPA 架构。
理解 ASP.NET Core 中 SPAs 的结构
在适当的架构下,功能可以轻松开发,并且我们可以达到出色的客户满意度。这种方法具有挑战性,因为它需要坚实的架构专业知识和适当的主机方法,但总是能够成功交付一个合理的解决方案。
在本节中,我们将了解 ASP.NET Core 中 SPAs 的结构。我们将探索三个最现代的 SPA 技术(Angular、React 和 Vue)的项目结构。
Angular SPAs
Angular 提供了一个完整的 MVC 模式实现。它仍然是用于构建 SPA 的最佳 JavaScript 框架之一。今天,使用最新的Visual Studio版本,我们可以创建一个启用 Angular 的新 ASP.NET Web 应用。
该项目将是 Angular ClientApp文件夹与通常包含在Controllers文件夹中的 Web API 的组合,如下面的截图所示:

图 9.4:使用 ASP.NET Core 的 Angular 应用结构
ClientApp文件夹通常包含与基于 Angular CLI 的前端应用相关的所有文件,而Controllers文件夹包含所有 API 端点。以下列表解释了前一个截图所示的 Angular 客户端应用下的主要文件和文件夹:
-
e2e: 这个文件夹用于创建不同类型的测试,它依赖于一个名为Protractor的测试库。 -
src: 这个文件夹包含我们将开发以渲染组件的前端代码;我们将大部分时间都花在这个文件夹中编写代码。它包括样式文件以及运行应用的配置文件。 -
angular.json: 这是一个配置文件,我们可以在这里指定应用的起始 HTML 页面以及应用开始执行时应执行的主要 TypeScript 文件。 -
.editorconfig: 这是一个配置文件,我们在这里设置编辑器在添加或修改 Angular 应用中的文件时应应用的设置。 -
package.json: 这个文件包含需要用于开发和部署应用的所有依赖项列表。 -
README.md: 默认情况下,这个文件包含的是 Markdown 格式的项目基本文档。 -
tsconfig.json: 这个文件包含了 TypeScript 编译器所需的配置。 -
tslint.json: 这个文件包含了一组规则,这些规则应由tslint工具检查以验证 TypeScript 代码的质量。
React SPA
React 是用于构建快速和交互式 SPA 的最受欢迎的 JavaScript 库之一。它主要关注应用程序的视图部分,主要是 UI 组件,因此需要使用额外的库来构建整个 SPA。
在 Visual Studio 中,我们可以利用现有的项目模板来创建一个新的 ASP.NET Core 应用程序,并使用 React。以下截图显示了 React 应用程序的项目结构。ClientApp 文件夹包含所有与 React 相关的文件,我们可以看到 Controllers 文件夹,其中包含 .NET Web API:

图 9.5:React 应用程序与 ASP.NET Core 的结构
以下列表解释了前一个截图所示的 React 客户端应用程序下的主要文件和文件夹:
-
public: 此文件夹包含应用程序的静态文件,例如 HTML 索引页面。 -
src: 此文件夹包含我们将要开发的全部动态组件。它还包含App.js文件,该文件充当主index.js文件,它代表应用程序的入口点,触发registerServiceWorker.js文件,该文件用于缓存应用程序的资产。这种缓存机制有助于加快应用程序的加载速度,并允许离线功能。 -
package.json: 此文件包含应用程序中使用的依赖项列表。
Vue SPA
Vue 是一个 JavaScript 框架,当与其他库结合使用时,用于构建现代单页应用(SPA)。与其他单体框架不同,Vue 是一个轻量级且易于学习的框架。在 Visual Studio 中,我们可以创建一个带有 Vue 的 ASP.NET Core 应用程序。
与其他项目模板类似,Vue 文件包含在 ClientApp 文件夹和 Controllers 文件夹中,后者包含 Web API 控制器,如下面的截图所示:

图 9.6:Vue 应用程序与 ASP.NET Core 的结构
以下列表解释了前一个截图所示的 React 客户端应用程序下的主要文件和文件夹:
-
public: 此文件夹包含应用程序的静态文件,例如 HTML 索引页面。 -
src: 此文件夹包含我们将要开发的全部动态组件。它还包含App.vue文件,该文件充当应用程序的根组件。main.jsJavaScript 文件负责初始化根组件并引入所需的插件。至于assets文件夹,它包含所有静态资产,例如 CSS 文件和图片。 -
package.json: 此文件包含应用程序中使用的依赖项列表。
在对这三个框架(Angular、React 和 Vue)的结构进行快速概述之后,我们可能会问自己,我们应该使用哪个框架? 这个问题很难回答,因为很难找到一个适用于所有情况的框架。以下是一个表格,展示了这三个框架之间的快速比较:

图 9.7:Angular、React 和 Vue 之间的快速比较
尽管 Angular 和 React 是构建具有复杂组件和非常动态内容的规模化和企业级网络解决方案的完美框架,但在 React 中编写代码比在 Angular 中更容易、更快。根据 2020 年进行的 Stack Overflow 开发者调查,React 是仅次于jQuery的第二大流行框架:insights.stackoverflow.com/survey/2020#most-popular-technologies。
虽然 Vue 轻量级且易于学习,但在三个框架中它展现了最佳的性能。此外,与 React 和 Angular 相比,Vue 的开发社区正在稳步增长。
在下一节中,我们将了解使用 Azure 托管我们的 Web 应用程序的三个主要选项。
探索 Azure 托管建议
Azure 托管为所有行业中的每个企业提供强大的托管能力,无论网络应用服务于哪个领域。它提供了一系列云服务,支持我们托管和扩展网络解决方案。它帮助我们应对业务挑战,而不是花费时间专注于我们需要托管解决方案的基础设施。
在 Azure 中有三种托管 Web 应用程序的方法:
-
App Service Web Apps
-
容器
-
虚拟机(VMs)
App Service Web Apps 是大多数场景下推荐的托管方法,因为它提供了一种完全管理的平台即服务(PaaS),以优化方式让我们的客户专注于他们的业务,而 Azure 则负责所需的基础设施,包括扩展应用程序。此外,我们可以利用 Azure 静态 Web 应用自动部署使用 Angular、React 和 Vue 等库和框架构建的全栈 Web 应用,这些应用可以从 GitHub 或 Azure DevOps 上的代码仓库部署到 Azure。
重要提示:
查阅 Microsoft 文档以获取有关使用 Azure App Service 分步部署过程的更多信息:docs.microsoft.com/en-us/learn/modules/host-a-web-app-with-azure-app-service/。这里还有一个链接:docs.microsoft.com/en-us/learn/paths/deploy-a-website-with-azure-app-service/。
对于实现微服务架构的应用程序,建议使用基于容器的方案来托管它们。
重要提示:
这里是一个如何在 Azure 门户中使用 Azure 门户部署容器实例的 Microsoft 参考链接:docs.microsoft.com/en-us/azure/container-instances/container-instances-quickstart-portal。这里还有一个关于如何在 Azure 中使用 Docker CLI 部署容器实例的参考链接:docs.microsoft.com/en-us/azure/container-instances/quickstart-docker-cli。
如果您的应用程序尚未完全准备好在云中托管,并且您希望对托管环境有更多的控制,您可以选择Azure 虚拟机,这是一种基础设施即服务(IaaS)。然而,如果您选择此选项,您必须考虑您需要持续维护工作来管理虚拟机环境并保持其更新。
重要提示:
这里是一个如何在 Azure 门户中创建 Windows 虚拟机的参考:docs.microsoft.com/en-us/azure/virtual-machines/windows/quick-create-portal。这里是一个如何在 Azure 门户中创建 Linux 虚拟机的 Microsoft 参考:docs.microsoft.com/en-us/azure/virtual-machines/linux/quick-create-portal。这里还有一个关于如何使用 Azure 虚拟机部署网站的逐步指南:docs.microsoft.com/en-us/learn/paths/deploy-a-website-with-azure-virtual-machines/。
摘要
在本章中,我们探讨了构建可扩展和云托管解决方案时必须了解的现代 Web 解决方案的一些关键特性。我们了解了传统 Web 应用程序和单页应用程序(SPAs)之间的区别,以及如何在这两者之间进行选择。
此外,我们还概述了使用 ASP.NET Core Web API 构建 SPAs 的三个现代前端框架的项目结构,并提供了这些框架之间的快速比较表。在本章的后面部分,我们探讨了在 Azure 中托管 Web 应用程序的主要选项,并提供了如何选择最适合我们解决方案的托管方法的建议。
在下一章中,我们将深入探讨设计和实施Microsoft DevOps解决方案,并了解它们的益处。
第十章:第十章:设计和实现 Microsoft DevOps 解决方案
在上一章中,我们学习了现代 Web 解决方案的关键特性。我们还探讨了三个主要前端框架的项目结构,并提供了快速比较。然后我们学习了 Azure 中的三种托管选项以及如何为我们的解决方案选择最佳托管方法。
在本章中,我们将学习如何在构建 Microsoft 解决方案的同时,有效地规划和管理工作流程。Azure DevOps 提供了一套现代工具,使我们能够更智能地规划并更快地开发产品。它还提供了团队成员之间坚实的协作,以交付质量更高的产品。
在本章中,我们将涵盖以下主题:
-
使用Azure Boards探索敏捷规划
-
了解源代码管理
-
理解 Git 仓库,包括分支和拉取请求
-
了解Azure Artifacts
-
理解 CI/CD 实践的逻辑
到本章结束时,我们将学习如何利用 DevOps 使用现代软件开发实践构建、测试和部署我们的应用程序。此外,我们将了解工作项,并学习Git及其主要功能。我们还将探索如何使用 Azure Artifacts 管理包,以及理解持续集成/持续开发(CI/CD)实践。
现在,让我们看看现代 Web 解决方案的关键特性。
使用 Azure Boards 探索敏捷规划
Azure Boards 是Microsoft作为 Azure DevOps 服务的一部分提供的一项服务。它提供了一套用于管理软件项目整个生命周期的功能和能力。它包括管理工作项、冲刺和待办事项的工具。此外,它还提供端到端预定义和可定制的仪表板,使我们能够深入了解项目活动的全貌,同时查看关键的KPI和指标,以了解项目进展情况。
让我们从探索 Azure Boards 的核心功能开始。
介绍工作项
工作项是 Azure DevOps 的核心组件,可以帮助我们的敏捷团队管理日常工作,组织冲刺,并在待办事项中优先处理任务。工作项可以是一般任务、问题或需求。以下截图显示了工作项的主页:

图 10.1:工作项主页
上一张截图代表所有工作项的主页,我们可以根据特定标准筛选项目。我们还可以分配项目、添加新项目和管理现有项目。此页面为每个参与项目的人提供了一个完整的进度视图,包括每个项目的状态以及谁在做什么。我们可以筛选以查看计划在下一个冲刺中交付的任务。
我们还可以指定项目之间的依赖关系,将大型任务分解成更小、更易于管理的项目,以及创建查询并保存以供以后使用。查询是所有工作项的过滤视图。例如,我们可以创建一个查询来显示活动任务,或者创建一个查询来显示分配给特定团队成员的任务。
创建新的工作项很容易。如图所示,我们只需点击新建工作项,然后选择类型;即史诗级任务、问题或任务:

图 10.2:创建新工作项的动作菜单
在动作菜单中,我们可以看到三种主要类型的工作项:
-
史诗级任务: 这代表了一个对产品功能至关重要的较大项目。它可以被分解成更小的用户故事。用户故事是史诗级任务中的一个特定工作项。例如,假设我们收到了一个为电子商务网站实现登录机制的需求。在这种情况下,史诗级任务代表了这个需求。这里的用户故事可能包括通过电子邮件登录、通过谷歌登录、通过 Facebook 登录和忘记密码。
-
功能: 这代表满足用户需求的功能的主体。功能是一系列用户故事,它提供了业务价值和软件产品的上下文。
-
角色-功能-收益模板:作为一个(用户角色),我想要(一个动作/目标)以便(一个收益/原因);例如:作为一个(客户),我想要(购物车功能)以便(我可以在线购买商品并支付)。 -
问题: 这代表了我们可能在开发产品过程中捕获的 bug、代码缺陷和软件问题。
-
任务: 这代表了一个作为构建产品一部分计划的工作项。这可能是由问题或需求引起的,包括需求分析、开发或测试。
以下截图显示了样本工作项的详情页面:

图 10.3:bug 项目详情页面
在详情页面,我们可以看到每个工作项都有一个带有唯一 ID 的标题、状态和迭代,如果它是缺陷,则包括复现步骤,如果它是需求,则包括项目描述。
我们还可以看到附加到工作项上的评论。这些代表了团队成员之间关于此工作项的讨论。我们可以跟踪工作项,以便在更新时接收通知。我们还可以将其分配给团队成员,例如,通过将问题链接到任务或史诗级任务来链接到另一个工作项。
在下一节中,我们将学习如何使用工作项来报告和组织工作。
探索看板、待办事项和冲刺
在上一节中,我们学习了关于工作项的内容,所以让我们学习如何在看板、待办事项和冲刺中使用它们来组织和跟踪团队的可交付成果。
以下截图显示了创建项目时关联的示例板:

图 10.4:示例看板
每次我们创建一个新的项目时,都会创建一个预配置的看板,并将其链接到项目,以便我们可以可视化工作项的进度。这个板是完全可定制的。我们可以将项目从一个类别拖放到另一个类别,以反映项目的当前情况。我们还可以根据状态、所有权、冲刺或其他任何标准来组织任务。
待办事项帮助我们根据优先级来保持事物组织有序。如图所示,待办事项提供了一个平铺的工作项视图,而看板则将它们显示为卡片:

图 10.5:待办事项列表视图
产品待办事项应该反映我们计划在即将到来的冲刺中交付的计划和路线图。
最后,冲刺是 DevOps 的脉搏,因为它们代表了敏捷项目的迭代。一个冲刺有自己的容量计划和任务板。在持续时间上应该较短,通常为 1 到 4 周;在这个期间,必须有一系列工作项,这些工作项应由团队完成。以下截图显示了示例冲刺视图:

图 10.6:冲刺视图
在前面的截图中,我们可以看到任务是如何在任务板区域中组织的,以反映冲刺的计划。我们可以在不同的类别之间拖放项目,并且可以检查这个冲刺中团队的总体进度。
重要提示:
了解和了解与 Azure Boards 相关的所有内容的 Microsoft 文档可以在docs.microsoft.com/en-us/azure/devops/boards/?view=azure-devops找到。
在本节中,我们学习了如何定义项目路线图和计划工作项。这有助于我们的团队通过使用 Azure DevOps 的强大平台将复杂解决方案分解为可管理的负载。在下一节中,我们将学习 Azure DevOps 中的源代码控制。
开始使用源代码控制
源代码控制(也称为版本控制)是 DevOps 的一个基本组成部分。它是一个协作平台,开发团队可以使用它来跟踪和管理源代码中的更改。它为项目中的每个源代码文件提供历史版本。它还有助于在合并来自多个开发者的更改时解决冲突。Azure Repos是一组版本控制工具,我们可以使用它来管理我们的代码。
这里是一份源代码控制的好处列表:
-
能够为开发、生产和测试创建多个工作流程。
-
在多个开发者共同参与同一项目时,为了交付产品,开发团队必须进行大量的协作,尤其是在源代码层面,以维护一个共同的仓库。
-
版本控制支持我们跟踪和管理多个团队成员对代码所做的所有更改。这在需要解决多个开发者尝试修改同一文件时产生的冲突时尤为重要。
-
通过允许我们检索仓库中每个文件的完整历史记录来维护更改的历史。
-
能够对源代码进行标记以跟踪产品版本,尤其是在我们有多版本发布时。我们还可以创建分支来管理生产环境和开发环境之间的开发活动。
Azure Repos 提供两种类型的版本控制:
-
团队基础版本控制(TFVC):代码历史记录集中存储在服务器上,团队成员需要连接到服务器进行提交。
-
Git:代码历史记录分布在每个团队成员的机器上,他们可以在本地提交更改。
扩展 Git 以支持企业 DevOps
Git 是开发团队和公司采用的最重要版本控制系统之一。Git 是一个分布式版本控制系统,这意味着存储在每个机器上的源代码本地副本代表了一个完整的版本控制仓库。
在本节中,我们将了解更多关于 Git 以及如何结构化仓库、管理分支和通过拉取请求进行协作。
结构化 Git 仓库
我们可以使用两种类型的仓库与 Git 一起使用:
-
单仓库:多个项目存储在单个仓库中
-
多仓库: 每个项目都有自己的仓库
单仓库与多仓库;哪种方法更合适? 没有直接的答案可以推荐特定的方法。我们选择用于结构化仓库的策略完全基于我们管理项目的方式;两种类型都有其优缺点。然而,值得一提的是 Facebook 和 Google 使用单仓库来管理他们的项目。以下是一些关键点,以帮助您决定遵循哪种策略:
-
单仓库简化了管理依赖关系,如果使用多仓库,这些依赖关系可能会变得复杂。
-
在单仓库中,我们可能会遇到一些性能上的缺点,尤其是在大型代码库的情况下。这在多仓库中不是问题。
-
在单仓库中强制执行共同实践和标准比在多仓库中更容易。
-
多仓库允许我们通过使每个微服务团队能够独立工作以更快地完成工作来提高工作效率。这使我们能够授予开发者访问他们需要的仓库。
使用 Git 的分支策略
Git 分支是代码更改快照的有效引用。分支提供了一种方法,可以将与新的功能或热修复相关联的更改从代码的主分支中隔离出来。提交到一个分支的代码更改不会自动影响其他分支,除非我们合并更改。
采取分支策略并遵循以下三个概念使其变得简单是至关重要的:
-
为每个特定版本的每个功能或功能集创建一个新的分支。这在修复缺陷后发布热修复补丁的情况下也适用。
-
使用拉取请求将子分支合并到主分支。除非代码已经经过适当的测试,并且确保受影响的函数正常工作并经过认证,否则不要将代码合并到主分支中。
-
保持主分支的最新状态,并且永远不要直接在其中修改代码。
以下图表展示了所有子分支如何合并它们的更新到主分支:

图 10.7:将子分支合并到主分支
你可以实现许多分支策略。最重要的是通过创建两个独立的分支来将开发活动与生产代码分离。我们可以遵循的策略之一是以下图表中所示的基于主干线的分支策略:

图 10.8:基于主干线的分支策略
在前面的图表中,我们可以看到两个主要分支:开发分支(Dev)和生产分支(Main)。这里的理念是我们永远不会直接在Main分支中编写代码。相反,我们需要为热修复创建一个分支;同时,热修复应该在适当的测试后与Dev分支合并。
对于发布分支,它通常从开发分支创建。经过开发和适当的测试后,它与生产分支和开发分支合并。这样,我们确保Main分支包含代码的生产版本,而Dev分支包含开发分支。
Git 分支创建和维护成本低廉。因此,如图所示,我们创建了一个单独的分支。即使是小的修复和更改也应该有自己的功能分支,这样可以简化更改历史的审查。在创建新分支时,提供有关分支的描述性信息并将其链接到工作项是很重要的。
在 Azure 仓库中通过拉取请求进行协作
拉取请求是通知团队领导或代码审查者新功能开发或错误修复已完成,并且代码在合并到主分支之前必须进行审查的强大机制。避免在没有拉取请求的情况下将代码合并到主分支,这强制执行了代码审查流程。这对于提高代码质量至关重要。
显然,如果审查过程后收到的反馈良好且符合标准,它可能会提高代码的质量。因此,建议您提供高质量的反馈。以下是一些成功的拉取请求的关键建议:
-
拥有合适的人来审查拉取请求并提供反馈是进行更好审查的关键因素。
-
建议在审查过程中有两个审查者作为最佳数量。
-
提供可操作和建设性的反馈非常重要。
-
及时回复评论以加速拉取请求流程很重要,尤其是如果您有大量请求在队列中。
-
在分支描述中提供足够的细节有助于审阅者理解变更的目的。
-
如果您已经实施了代码审查会议,建议将其与拉取请求流程结合起来,以避免重复工作。
在本节中,我们了解了可以在 Git 仓库中使用的结构化选项,以及如何在这之间进行选择。我们还探索了一些更好的分支策略的建议,并讨论了拉取请求流程的好处。然后我们强调了提高这一流程的一些关键因素。在下一节中,我们将学习如何设置良好的依赖关系管理策略。
使用 Azure Artifacts 管理包
Azure Artifacts是 Azure DevOps 中的一个扩展,它提供了一组使用NuGet、npm和Maven创建和管理包的能力。这可以帮助我们管理代码库中的依赖关系并将它们分组到源中。在 Azure Artifacts 中创建的每个源都有自己的 URL,我们可以从Visual Studio中消费这些 URL 来将包安装到我们的解决方案中;开发团队也可以使用相同的源 URL 来发布私有包。
只要包和工件的大小小于2 GB,Azure Artifacts 是免费的。超过 2 GB 的所有内容都将根据订阅计划收费。以下页面可以在 Azure Artifacts 的左侧菜单中找到,紧邻以下截图中的箭头所示:

图 10.9:Azure Artifacts 中的包源
在前面的截图中,我们有一个名为CMSArtifacts的源。在这个源中,我们可以看到一组被添加到这个容器中的包。这里的目的是将我们在解决方案中使用的公共和私有包组织到一个可以被开发团队消费的源中。
使用 Azure Artifacts,我们可以创建饲料的视图。例如,我们可以为开发环境中使用的包创建一个视图,并为产品的生产版本创建另一个视图。
以下截图显示了同一饲料的三个不同视图;即本地、预发布和发布。每个视图都包含特定版本的包,并且用于特定的工作环境:

图 10.10:饲料视图
如我们所见,前一个截图中有三个视图。这些视图是与饲料一起创建的。我们仍然可以添加新的视图或修改现有的视图。
上游源,如图所示,允许我们将创建的包和从远程饲料中消费的包在同一个地方分组。以下截图显示了我们可以用来创建上游的界面。请注意,我们可以指定我们想要用于上游的视图类型:

图 10.11:添加具有特定视图的上游源
每个上游源都链接到一个视图,这就是我们如何通过上游源在 Visual Studio 中使用视图。
在本节中,我们介绍了 Azure Artifacts,它支持多饲料方法。我们可以利用它来组织和分组我们在项目中使用的包。有关如何创建和管理 Azure Artifacts 的更多技术信息,请参阅 Microsoft 文档:docs.microsoft.com/en-us/azure/devops/artifacts/overview?view=azure-devops。
在下一节中,我们将探索使用 Azure Pipelines 的持续集成。
使用 Azure Pipelines 探索 CI/CD
持续集成、持续交付和持续部署(或CI/CD)是使用 DevOps 中的现代软件开发技术构建、测试和部署健壮应用程序的主要支柱。这些实践使我们能够通过自动化流程快速发布新功能和修复。让我们了解这些实践中的每一个。
持续集成(CI)是 DevOps 中的核心实践。它允许我们将来自多个开发者的所有源代码修改频繁地集成到主仓库中。这是一个可以在 Azure DevOps 中配置的自动化流程。当此功能启用时,每次开发者提交代码时,CI 都将通过启动自动化构建过程来验证项目是否包含构建错误。之后,将触发自动化测试过程以确认新提交的代码是稳定的。这种方法对于快速轻松地识别错误非常有帮助。
連續交付是一種實踐,它自動化了建設和測試階段之後的交付步驟。無論何時我們都有成功的建設和測試,都會觸發一個自動流程將工件部署到目標環境。這可以是測試環境或生產環境。注意,在這種實踐中,從測試環境將代碼發送到生產環境是通過人工介入完成的。
連續部署與連續交付有很多相似之處。主要差異在於這種實踐自動化了發布流程的整個生命周期,並將工件自動部署到生產環境。
以下圖表展示了每種實踐的步驟:

圖 10.12:CI/CD 步驟
在先前的圖表中,除非完成連續集成流程,否則連續交付和連續部署流程都不能啟動。連續交付和連續部署之間的步驟幾乎相同;然而,在連續交付中,生產部署是通過手動任務完成的,而在連續部署中,它是一個自動流程。
要實施構建策略,我們需要利用 Azure DevOps 中的管道。管道是一種自動化服務,用於驗證構建並使其準備就緒以部署。管道的使用將減少開發者為合併代碼、構建它和測試變更以及受影響的功能所需的人工工作。重要的是要提到,管道用於連續交付和連續部署以自動化其步驟。
總結
在本章中,我们探讨了 Azure DevOps 中敏捷规划的基礎程序。我們還學習了 Azure Boards,以及相關的组件,如工作項、待辦事項和迭代。然後,我們討論了源控制,並解釋了 TFVC 和 Git 之間的差異。
之後,我們探索了 Git 及其如何版本控制源代碼,然後學習了分支和拉取請求。稍後,我們學習了 Azure Artifacts 中可用的包,以及 CI/CD,它們幫助自動化與構建、測試和部署我們的代碼相關的步驟。
現在你已經讀完這本書,你的腦海裡可能充滿了許多不同的想法,因為你已深入了解了解決方案架構的日常方面。我建議你從衡量你在成為有效解決方案架構師的旅程中處於何種位置開始。一個好的解決方案架構師幫助建立適合現有環境並滿足客戶需求的優質產品。為了實現這一點,解決方案架構師必須了解商業模式的每一部分以及這些部分是如何相互合作的。
本书涵盖了众多主题。然而,经常进行研究和了解解决方案架构中的新技术和模式,培养一种学习心态,以及专注于 Azure 提供的云服务以构建现代解决方案,这是一种良好的实践。同时,不断提高我们的软技能至关重要,尤其是如果我们想成为有效的领导者。我希望您阅读这本书的乐趣与我写作和分享我的想法和经验一样多。祝您在所有.NET 项目中取得成功!

订阅我们的在线数字图书馆,全面访问超过 7,000 本书和视频,以及领先的行业工具,帮助您规划个人发展并提升职业生涯。更多信息,请访问我们的网站。
第十一章:为什么订阅?
-
通过来自 4,000 多位行业专业人士的实用电子书和视频,节省学习时间,增加编码时间
-
通过为您量身定制的技能计划提高学习效果
-
每月免费获得一本电子书或视频
-
完全可搜索,便于轻松访问关键信息
-
复制粘贴、打印和收藏内容
您知道 Packt 为每本书都提供电子书版本,包括 PDF 和 ePub 文件吗?您可以在 packt.com 升级到电子书版本,并且作为印刷版书籍的顾客,您有权获得电子书副本的折扣。有关更多信息,请联系我们 customercare@packtpub.com。
在 www.packt.com 上,您还可以阅读一系列免费的技术文章,注册各种免费通讯,并享受 Packt 书籍和电子书的独家折扣和优惠。
您可能还喜欢的其他书籍
如果您喜欢这本书,您可能对 Packt 出版的以下其他书籍也感兴趣:
使用 C# 9 和 .NET 5 进行企业级应用程序开发
拉文德拉·阿凯拉,阿伦·库马尔·塔米里斯,苏尼尔·库马尔·库纳尼,布普什·古普塔·穆蒂亚卢
ISBN: 978-1-80020-944-2
-
通过充分利用 .NET 5 的最新功能来设计企业应用程序
-
发现应用程序的不同层,如数据层、API 层和 Web 层
-
探索端到端架构,使用 .NET 和 C# 9 实现企业级网络应用程序,并在 Azure 上部署应用程序
-
关注网络应用程序开发的核心理念,如依赖注入、缓存、日志记录、配置和身份验证,并在 .NET 5 中实现它们
-
将新的 .NET 5 健康和性能检查 API 集成到您的应用程序中
-
了解 .NET 5 的工作原理并为其平台做出贡献
使用 C# 9 和 .NET 5 进行企业级应用程序开发
加布里埃尔·巴普蒂斯塔,弗朗西斯科·阿布鲁齐塞
ISBN: 978-1-80056-604-0
-
使用不同的技术克服现实世界的架构挑战并解决设计考虑事项
-
应用分层架构、面向服务的架构(SOA)和微服务等架构方法
-
利用容器、Docker、Kubernetes 和 Blazor 等工具有效地管理微服务
-
熟悉 Azure 工具和功能,以提供全球解决方案
-
使用 C# 9 和其最新功能编程和维护 Azure Functions
-
理解何时使用测试驱动开发(TDD)作为软件开发的方法最为合适
-
编写自动化的功能测试用例
-
获取 DevOps 原则的最佳实践以启用 CI/CD 环境
Packt 正在寻找像你这样的作者
如果你有兴趣成为 Packt 的作者,请访问 authors.packtpub.com 并今天申请。我们已与成千上万的开发者和技术专业人士合作,就像你一样,帮助他们将见解与全球技术社区分享。你可以提交一般申请,申请我们正在招募作者的特定热门话题,或者提交你自己的想法。
分享你的想法
现在你已经完成了 《.NET 解决方案架构》,我们非常想听听你的想法!如果你从亚马逊购买了这本书,请点击此处直接进入该书的亚马逊评论页面并分享你的反馈或在该购买网站上留下评论。
你的评论对我们和整个技术社区都至关重要,并将帮助我们确保我们提供高质量的内容。


浙公网安备 33010602011771号