一、你好 Blazor

感谢您用 Blazor 获取您的网络开发副本。这本书旨在让你尽可能快速、无痛苦地开始,一章一章,而不必在开始阅读之前从头到尾阅读这本书。

这本书将从指导您开始 Blazor 之旅时遇到的最常见场景开始,还将深入探讨一些更高级的场景。这本书的目标是向你展示什么是 Blazor——Blazor 服务器和 Blazor 网络组装——它是如何实际工作的,并帮助你避免一路上的任何陷阱。

人们普遍认为 Blazor 是 WebAssembly,但 WebAssembly 只是运行 Blazor 的一种方式。Blazor 上的许多书籍、研讨会和博客文章都非常关注网络组装。这本书将涵盖网络组装和服务器端。Blazor 服务器和 Blazor WebAssembly 之间有一些区别,我将在后面指出这些区别。

这第一章将探究 Blazor 从何而来,是什么技术使 Blazor 成为可能,以及运行 Blazor 的不同方式。我们还将讨论哪种类型最适合您。

在本章中,我们将涵盖以下主题:

  • Blazor 之前
  • 介绍网络组装
  • 介绍.NET 5
  • 介绍 Blazor

技术要求

建议您了解.NET,因为这本书的目标是.NET 开发人员,他们希望利用自己的技能来制作交互式网络应用。然而,你很有可能会捡到一些。如果你是. NET 世界的新手,一路上会遇到很多技巧

在 Blazor 之前

你可能没有读到这本书关于 JavaScript 的内容,但是记住我们来自一个 Blazor 时代之前的 T2 是有帮助的。我记得那个时代——黑暗时代。Blazor 中使用的许多概念与许多 JavaScript 框架中使用的概念相差不远,因此我将首先简要概述我们面临的挑战。

作为开发人员,我们有许多不同的平台可以开发,包括桌面、移动、游戏、云(或服务器端)、人工智能,甚至物联网。所有这些平台都有许多不同的语言可供选择,但当然还有一个平台:在浏览器内部运行的应用。

我已经做了很长时间的 web 开发人员,我已经看到代码从服务器上转移,这样它就可以在浏览器中运行。它改变了我们开发应用的方式。Angular、React、Aurelia 和 Vue 等框架已经改变了网络,从必须重新加载整个页面到动态更新页面的一小部分。这个新的动态更新方法使得页面加载更快,因为感知的加载时间降低了(不一定是整个页面加载)。

但是对于很多开发者来说,这是一个全新的技能集需要学习;也就是说,在服务器(很可能是 C#,如果你正在读这本书的话)和用 JavaScript 开发的前端之间切换。数据对象在后端用 C#编写,然后序列化为 JSON,通过 API 发送,然后在前端反序列化为另一个用 JavaScript 编写的对象。

JavaScript 使用在不同的浏览器中以不同的方式工作,jQuery 试图通过拥有一个通用的 API 来解决这个问题,该 API 被翻译成网络浏览器可以理解的东西。现在,不同 web 浏览器之间的差异要小得多,这使得 jQuery 在许多情况下已经过时。

例如,JavaScript 与其他语言有点不同,因为它不是面向对象的或类型化的。2010 年,安德斯·海尔斯伯格(以 C#、Delphi 和 Turbo Pascal 的原始语言设计者而闻名)开始着手于 TypeScript 的工作,这是一种可以编译成 JavaScript 的面向对象语言。

您可以将 Typescript 与 Angular、React、Aurelia 和 Vue 一起使用,但最终运行实际代码的是 JavaScript。简而言之,要使用 JavaScript/TypeScript 创建当今的交互式网络应用,您需要在语言之间切换,并且还要选择和跟上不同的框架。

在这本书里,我们将以另一种方式看待这个问题。尽管我们将讨论 JavaScript,但我们的主要重点将是开发主要使用 C#的交互式网络应用。

现在,我们知道了一些关于 JavaScript 的历史。由于 WebAssembly,JavaScript 不再是唯一可以在浏览器中运行的语言,我们将在下一节中介绍它。

介绍网络组装

在本节中,我们将了解网络组件的工作原理。运行 Blazor 的一种方法是使用 WebAssembly,但是现在,让我们专注于什么是 WebAssembly。

WebAssembly 是一种经过编译的二进制指令格式,因此更小。它是为本机速度而设计的,这意味着在速度方面,它更接近 C++而不是 JavaScript。加载 JavaScript 时,会下载、解析、优化和 JIT 编译 JS 文件(或内联文件);当涉及到 WebAssembly 时,大多数这些步骤都是不需要的。

WebAssembly 有一个非常严格的安全模型,可以保护用户免受错误或恶意代码的侵害。它在一个沙箱中运行,如果不通过适当的 API,就无法逃离该沙箱。如果你想在 WebAssembly 之外进行通信,例如,通过更改文档对象模型 ( DOM )或从 web 下载文件,你将需要通过 JavaScript interop 来实现(稍后会有更多相关内容,别担心——Blazor 会为我们解决这个问题)。

为了更熟悉网络组装,让我们看一些代码。

在这一部分,我们将创建一个应用,将两个数字相加并返回结果,用 C 语言编写(老实说,这大约是我所熟悉的 C 语言水平)。

我们可以通过几个简单的步骤将 C 编译成 WebAssembly:

  1. 导航至https://wasdk.github.io/WasmFiddle/
  2. 添加以下代码:

    cs int main() { return 1+2; }

  3. 建立,然后运行

您将看到数字3显示在页面底部的输出窗口中,如下图所示:

Figure 1.1 – WasmFiddle

图 1.1–WasmFiddle

WebAssembly 是一种堆栈机器语言,这意味着它使用堆栈来执行其操作。

请考虑以下代码:

1+2

大多数编译器(包括我们刚才用的那个)都是去优化代码,简单的返回3

但是让我们假设所有的指令都应该被执行。这是网络组装的方式:

  1. 首先将1推到堆栈上(instruction: i32.const 1),然后将2推到堆栈上(instruction: i32.const 2)。此时,堆栈包含12
  2. 然后,我们必须执行加法指令(i32.add),它将从堆栈中弹出(get)两个顶值(12),将它们相加,并将新值推送到堆栈中(3)。

这个演示展示了我们可以从 C 代码构建 WebAssembly。现在,我们有了在浏览器中运行的编译成网络程序集的 C 代码。

其他语言

一般只有低级语言才能编译成 WebAssembly(比如 C 或 Rust)。然而,有太多的语言可以运行在网络汇编之上。这里有大量这些语言的集合:https://github.com/appcypher/awesome-wasm-langs。

WebAssembly 的性能非常高(接近本地速度)——如此高的性能以至于游戏引擎已经为此采用了这项技术。Unity,以及虚幻引擎,都可以编译成 WebAssembly。

这里有几个在网络组件上运行的游戏的例子:

这是一个惊人的不同网络组装项目列表:https://github.com/mbasso/awesome-wasm

这一部分触及了网络组装的工作原理,在大多数情况下,您不需要知道更多。我们将在本章后面深入探讨 Blazor 如何使用这项技术。

要编写 Blazor 应用,我们必须利用的力量.NET 5,我们接下来会看它。

介绍.NET 5

要构建 Blazor 应用,我们必须使用.NET 5 。那个.NET 团队多年来一直在努力为我们开发人员收紧一切。他们一直在使一切变得更简单、更小、跨平台和开源,更不用说更容易利用您现有的知识.NET 开发。

.NET core 是迈向更统一的. NET 之旅的一步,它让微软重新审视了整个系统.NET 平台,并以全新的方式进行构建。

有三种不同的类型.NET 运行时:

  • 。. NET 框架(完整版.NET)
  • .NET Core
  • 猴子/洗发精

不同的运行时有不同的功能和性能。这也意味着创建一个. NET Core 应用(例如)需要安装不同的工具和框架。

.NET 5 是我们迈向单一. NET 之旅的开始。有了这个统一的工具链,创建、运行等体验将在所有不同的项目类型中保持一致。.NET 5 仍然是以我们习惯的类似方式模块化的,所以我们不必担心合并所有不同的.NET 版本将导致一个臃肿的. NET

多亏了.NET 平台,您将能够只使用 C#并使用相同的工具就可以到达我们在本章开头谈到的所有平台(web、桌面、移动、游戏、云(或服务器端)、AI,甚至 IoT)。

现在您已经了解了一些周围的技术,在下一节中,是时候介绍这本书的主角:Blazor 了。

介绍 Blazor

Blazor 是一个开源 web UI SPA 框架。在同一句话中有很多流行语,但简单地说,这意味着您可以使用 HTML、CSS 和 C#创建交互式 SPA 网络应用,完全支持绑定、事件、表单和验证、依赖注入、调试等。我们将看看这本书。

2017 年,史蒂夫·桑德森(以创建淘汰赛 JavaScript 框架而闻名,他在微软的 ASP.NET 团队工作)即将参加一个名为的会议,网络应用不可能真的做到这一点,对吗?在 NDC 奥斯陆的开发者大会上。

但是史蒂夫想展示一个很酷的演示,所以他对自己说,在 WebAssembly 中运行 C#可能吗?他在 GitHub 上发现了一个旧的不活跃的项目,名为 Dot Net Anywhere ,它是用 C 语言编写的,并且使用工具(类似于我们刚刚做的)将 C 代码编译成 WebAssembly。

他在浏览器中运行了一个简单的控制台应用。对大多数人来说,这将是一个惊人的演示,但史蒂夫想更进一步。他想,有没有可能在此基础上创建一个简单的 web 框架?,接着看他是否也能让工装正常工作。

到了他的会议时间,他有一个工作示例,在这里他可以创建一个新项目,创建一个具有强大工具支持的待办事项列表,然后在浏览器中运行该项目。

达米安·爱德华兹(the.NET 团队)和大卫·福勒(the.NET 团队)也参加了 NDC 会议。史蒂夫向他们展示了他将要演示的东西,他们描述了他们的头爆炸和下巴落下的事件。

Blazor 的原型就是这样产生的。

Blazor 这个名字来自于 Browser 和 Razor 的结合(这是一种用于将代码和 HTML 结合起来的技术)。增加一个 L 让名字听起来更好,但除此之外,它没有真正的含义或首字母缩写。

有几种不同风格的 Blazor 服务器,包括 Blazor WebAssembly、WebWindow 和移动绑定。不同版本有一些优点和缺点,我将在接下来的章节中介绍所有这些。

Blazor 服务器

Blazor 服务器使用 SignalR 在客户端和服务器之间进行通信,如下图所示:

Figure 1.2 – Overview of Blazor Server

图 1.2–Blazor 服务器概述

signor是一个开源的实时通信库,可以在客户端和服务器之间建立连接。SignalR 可以使用许多不同的方式传输数据,并根据您的服务器和客户端功能自动为您选择最佳的传输协议。SignalR 将一直尝试使用 WebSockets,这是一个内置在 HTML5 中的传输协议。如果由于任何原因没有启用网络套接字,它将优雅地退回到另一个协议。

Blazor 是用名为组件的可重用 UI 元素构建的(更多关于 第三章引入实体框架核心中的组件)。每个组件都包含 C#代码、标记,甚至可以包含另一个组件。如果你愿意,你可以使用 Razor 语法混合标记和 C#代码,甚至用 C#做任何事情。组件可以通过用户交互(按下按钮)或触发器(如计时器)来更新。

这些组件被渲染到一个渲染树中,这是一个包含对象状态和任何属性或值的二进制表示。渲染树将跟踪与前一个渲染树相比的任何变化,然后使用二进制格式仅发送通过 SignalR 更改的内容来更新 DOM。

在客户端,JavaScript 将接收到更改并相应地更新页面。如果我们将其与传统的 ASP.NET 进行比较,我们只呈现组件本身,而不是整个页面,并且我们只发送对 DOM 的实际更改,而不是整个页面。

当然,Blazor 服务器有一些缺点:

  • 您需要始终连接到服务器,因为渲染是在服务器上完成的。如果你有一个坏的互联网连接,该网站可能无法工作。与非 Blazor 服务器站点相比,最大的区别在于非 Blazor 服务器站点可以传递一个页面,然后断开连接,直到它请求另一个页面。使用 Blazor,必须始终连接该连接(信号员)(轻微断开也可以)。
  • 没有离线/PWA 模式,因为它需要连接。
  • 每次点击或页面更新都必须往返于服务器,这可能会导致更高的延迟。重要的是要记住,Blazor 服务器将只发送已更改的数据。我没有经历过任何缓慢的响应时间。
  • 因为我们必须连接到服务器,所以服务器上的负载会增加,并且难以扩展。要解决这个问题,您可以使用 Azure SignalR 集线器,它将处理持续的连接,并让您的服务器专注于传递内容。
  • 为了能够运行它,您必须将其托管在支持 ASP.NET Core 的服务器上。

然而,Blazor 服务器也有优势:

  • 它只包含足够的代码来建立下载到客户端的连接,这样站点的占用空间就很小。
  • 由于我们在服务器上运行,应用可以充分利用服务器的功能。
  • 该网站将在不支持网络组装的旧网络浏览器上运行。
  • 代码在服务器上运行并留在服务器上;没有办法对代码进行反编译。
  • 由于代码是在您的服务器(或云中)上执行的,您可以直接调用组织内的服务和数据库。

在我的工作场所,我们已经有了一个大型网站,所以我们决定在我们的项目中使用 Blazor Server。我们有一个客户门户和一个内部客户关系管理工具。我们的方法是一次获取一个组件,并将其转换为 Blazor 组件。

我们很快意识到,在大多数情况下,在 Blazor 中重新构建组件比继续使用 ASP.NET MVC 并在此基础上添加功能更快。随着我们的转换,终端用户的用户体验 ( UX )变得更好了。

页面加载得更快,我们可以根据需要重新加载页面的一部分,而不是整个页面,等等。

不过,我们确实发现 Blazor 引入了一个新问题:页面变得太快了。我们的用户不明白数据是否已经保存,因为什么都没发生;事情确实发生了,但是太快了,用户没有注意到。突然之间,我们不得不更多地考虑 UX,以及如何通知用户发生了变化。在我看来,这当然是 Blazor 非常积极的副作用。

Blazor 服务器并不是运行 Blazor 的唯一方法——您也可以使用 WebAssembly 在客户端(在 web 浏览器中)上运行它。

Blazor WebAssembly

还有一个选择:不用在服务器上运行 Blazor,你可以在你的网页浏览器里面使用 WebAssembly 运行它。

正如我们之前提到的,目前还没有办法将 C#编译成 WebAssembly。取而代之的是,微软采用了 mono 运行时(用 C 语言编写),并将其编译成了 WebAssembly。

Blazor 的 WebAssembly 版本与服务器版本非常相似,如下图所示。我们已经将所有内容从服务器上移除,现在它正在我们的网络浏览器中运行:

Figure 1.3 – Overview of  Blazor Web Assembly

图 1.3–Blazor 尔网组件概述

渲染树仍然被创建,并且不再在服务器上运行 Razor 页面,而是在我们的网络浏览器中运行。由于 WebAssembly 没有直接的 DOM 访问,Blazor 用直接的 JavaScript 互操作来更新 DOM,而不是 SignalR。

编译到网络汇编中的 mono 运行时叫做dotnet . wasm。该页面包含一小段 JavaScript,将确保加载dotnet.wasm。然后,它会下载blazor.boot.json,这是一个 JSON 文件,包含应用需要能够运行的所有文件,以及应用的入口点。

如果我们看一下在 Visual Studio 中启动一个新的 Blazor 项目时创建的默认示例站点,Blazor.boot.json文件包含 63 个需要下载的依赖项。所有依赖项都被下载,应用启动。

正如我们之前提到的,dotnet.wasm是编译到网络组件中的单声道运行时。它跑了.NET 动态链接库–您已经编写的动态链接库,以及.NET 框架(运行你的应用需要它)——在你的浏览器里面。

当我第一次听到这个的时候,我的嘴里有一点不好的味道。它正在运行整个.NET 运行时?!但是,过了一会儿,我意识到这有多神奇。你可以用任何一种.NET 标准动态链接库,并在您的网络浏览器中运行它们。

在下一章中,我们将看看当一个 WebAssembly 应用启动时,到底发生了什么,以及代码执行的顺序。

最大的担忧是网站的下载量。简单的文件新的示例应用的大小约为 1.3 MB,如果你在下载大小上投入大量精力,这是相当大的。不过,你应该记住的是,这更像是一个单页应用(SPA)——已经下载到客户端的是整个网站。我把规模和网上一些知名网站做了对比;然后我只包含了这些站点的 JS 文件,但也包含了 Blazor 的所有 dll 和 JavaScript 文件。

以下是我的发现图表:

Figure 1.4 – JavaScript download size for popular sites

图 1.4–热门网站的 JavaScript 下载量

即使其他站点比 Blazor 示例站点大,您也应该记住 Blazor DLLs 是编译的,应该比 JavaScript 文件占用更少的空间。WebAssembly 也比 JavaScript 快。

Blazor WebAssembly 有一些缺点:

  • 即使我们将其与其他大型网站进行比较,Blazor WebAssembly 的占地面积也很大,并且有大量文件需要下载。
  • 要访问任何现场资源,您需要创建一个网络应用编程接口来访问它们。您不能直接访问数据库。
  • 代码在浏览器中运行,这意味着它可以被反编译。这是所有应用开发人员都习惯的事情,但对于网络开发人员来说,这可能并不常见。

当然,Blazor WebAssembly 也有一些优势:

  • 由于代码在浏览器中运行,因此很容易创建进步网络应用 ( PWA )。
  • 因为我们没有在服务器上运行任何东西,所以我们可以使用任何类型的后端服务器,甚至文件共享(后端不需要. NET 兼容的服务器)。
  • 没有往返意味着你可以更快地更新屏幕(这就是为什么有使用网络组装的游戏引擎)。

我想把最后的优势付诸实践!当我 7 岁的时候,我得到了我的第一台电脑,一台辛克莱 ZX 频谱。我记得我坐下来写了以下内容:

10 PRINT "Jimmy"
20 GOTO 10 

那是我的代码;我让电脑一遍又一遍地在屏幕上写我的名字!

那一刻,我决定我想成为一名开发人员,这样我就可以让计算机做事情。

成为一名开发人员后,我想重温我的童年,并决定建立一个 ZX 频谱模拟器。在很多方面,当我遇到新技术的时候,模拟器已经成为我的测试项目,而不是简单的 Hello World 。我已经在 Gadgeteer、Xbox One 甚至全息镜头(仅举几个例子)上运行过它。

但是有可能在 Blazor 中运行我的模拟器吗?

我只花了几个小时就通过利用我已经构建的来让模拟器与 Blazor WebAssembly 一起工作.NET 标准动态链接库;我只需要编写特定于这个实现的代码,比如键盘和图形。这是 Blazor(服务器和 WebAssembly)如此强大的原因之一:它可以运行已经制作好的库。您不仅可以利用您的 C#知识,还可以利用大型生态系统和.NET 社区。

你可以在这里找到模拟器:https://zxspectrum.azurewebsites.net/.这是我最喜欢的工作项目之一,因为我一直在寻找优化和改进模拟器的方法。

构建这种类型的网络应用过去只能通过 JavaScript 实现。现在,我们知道可以使用 Blazor WebAssembly 和 Blazor Server,但是这些新选项中哪一个是最好的呢?

Blazor WebAssembly 对 Blazor 服务器

我们应该选择哪一个?答案是,一如既往,这取决于。你已经看到了两者的优缺点。

如果你有一个当前站点,你想移植到 Blazor,我会选择服务器端;一旦您移植了它,您就可以对是否也要使用 WebAssembly 做出新的决定。

如果您的站点运行在移动浏览器或其他不可靠的互联网连接上,您可能需要考虑使用 Blazor WebAssembly 进行离线(PWA)场景,因为 Blazor Server 需要持续的连接。

WebAssembly 的启动时间有点慢,但是有一些方法可以将两种宿主模型结合起来,这样就可以两全其美了。我们将在 第 9 章共享代码和资源中介绍这一点。

在这个问题上没有灵丹妙药,但是仔细阅读优点和缺点,看看它们如何影响您的项目和用例。

我们可以在服务器端和客户端运行 Blazor,但是桌面和移动应用呢?通过使用网络窗口和移动浏览器绑定,也有解决方案。

网络窗口

有一项实验性技术叫做网络窗口,这是史蒂夫·桑德森的一个开源项目。它使我们能够使用 Blazor 创建 Windows 应用。

WebWindow 不在本书的讨论范围之内,但我还是想提一下它,因为它展示了这项技术的真正强大,以及 Blazor 的无限可能性。

你可以在这里找到并阅读更多关于这个项目的信息:https://github.com/SteveSandersonMS/WebWindow

Blazor 移动绑定

另一个不在本书范围内但仍值得一提的项目例子是Blazor 移动绑定。这是一个利用 Blazor 为 iOS 和 Android 创建移动应用的项目。

Blazor 移动绑定像 Blazor 一样使用 Razor 语法;但是,组件完全不同。

虽然微软同时支持 Blazor 和 Blazor Mobile Bindings,但我们实际上无法在不同的 web 版本(WebAssembly、Server 或 WebWindow)之间共享代码。

你可以在这里找到并阅读更多关于这个项目的信息:https://docs.microsoft.com/en-us/mobile-blazor-bindings/

如你所见,你可以用 Blazor 做很多事情,而这只是开始。

总结

在这一章中,向您概述了可以与 Blazor 一起使用的不同技术,例如服务器端、客户端(WebAssembly)、桌面和移动。这个概述应该有助于您对下一个项目选择什么技术做出明智的决定。

然后我们讨论了 Blazor 是如何创建的,以及它的底层技术,比如 SignalR 和 WebAssembly。您还了解了渲染树以及 DOM 是如何更新的,从而让您了解 Blazor 在幕后是如何工作的。

在接下来的章节中,我将向您介绍各种场景,让您具备处理从升级旧的/现有的站点、创建新的服务器端站点到创建新的 WebAssembly 站点等一切事情的知识。

在下一章中,我们将通过配置我们的开发环境以及创建和检查我们的第一个 Blazor 应用来弄脏我们的手。

进一步阅读

作为一名. NET 开发人员,您可能会对 Uno 平台(https://platform.uno/)感兴趣,它使得在 XAML 创建 UI 并将其部署到许多不同的平台(包括 WebAssembly)成为可能。

如果你想看看 ZX 频谱模拟器是如何搭建的,可以在这里下载源代码:https://github.com/EngstromJimmy/ZXSpectrum