使用WebAssembly构建交互式 Blazor应用

 

目录

​编辑

.NET 8中的Blazor WebAssembly概述

静态服务器

渐进式增强

交互式WebAssembly

交互式服务器

Blazor交互式WebAssembly概述

Blazor WebAssembly选择

启动新的Blazor Web应用项目

服务器解决方案

客户解决方案

为Blazor WebAssembly编写组件

添加新组件

将HTTP客户端与Blazor交互式WebAssembly配合使用

服务器设置

最小API

客户端设置

持久化预渲染状态

结论


了解.NET 8中Blazor WebAssembly的新增功能,并创建第一个交互式WASM应用。

传统上,JavaScript开发与Web开发密不可分。然而,Web开发中出现了一条新途径,它提供了JavaScript的替代方案——WebAssembly。WebAssembly,通常缩写为WASM,是一种专为Web浏览器设计的二进制指令格式。它的主要目的是作为C++等高级语言的编译目标。

2017年,Microsoft发起了一项名为Blazor的WebAssembly实验,旨在将.NET引入浏览器。2019年,该实验正式成为ASP.NET Core及其长期支持发布周期的一部分。截至.NET 8,Blazor现已推出5年,并在功能、支持和开发人员采用方面继续增长。

本文将探讨.NET 8中引入的最新功能,深入研究Blazor WebAssembly的机制,概述支持的应用程序类型,并指导你完成使用.NET 8创建第一个Blazor交互式WebAssembly应用程序的过程。

.NET 8中的Blazor WebAssembly概述

Blazor WebAssembly通过在浏览器上运行.NET为.NET开发人员提供了使用JavaScript进行Web开发的替代方法。通过在浏览器中运行.NET,.NET库(DLL)无需重新编译即可在浏览器中工作。但是,这是以首次访问加载时间为代价的。当用户首次加载Blazor WebAssembly应用程序时,.NET运行时将下载到浏览器。这种首次访问加载时间对于用户体验(UX)和搜索引擎优化(SEO)至关重要。

在.NET 8中,包含了多种补救措施,以通过静态服务器端呈现(静态SSR)、渐进式增强和自动呈现模式来消除延迟。若要详细了解每种呈现模式以及与其关联的模板选项,请参阅统一Blazor Web应用项目模板完整说明一文。

静态服务器

静态SSR使用ASP.NET Razor组件在服务器上呈现静态HTML。顾名思义,静态SSR不提供任何交互性,并且依赖于Web标准表单POST。

渐进式增强

在.NET 8中,Blazor将传统的HTML和HTTP原则与现代方法无缝集成,提供从静态页面到完整的单页应用程序(SPA)的动态范围。通过采用渐进式增强技术(包括高级导航和表单处理),Blazor可有效减少页面加载时间并优化性能,实现和谐平衡,同时最大限度地减少相关权衡。

交互式WebAssembly

交互式WebAssembly使用Blazor WebAssembly在客户端中呈现组件。应用程序逻辑由.NET WebAssembly运行时执行。

交互式服务器

Blazor的呈现模式在.NET 8中变得非常广泛。在本文的范围内,我们将重点介绍交互式WebAssembly和渐进式增强的某些方面。扎实掌握这些概念将为您以后合并其他交互模式做好准备。

Blazor交互式WebAssembly概述

在传统的Web应用程序中,JavaScript用于解析、编译和执行代码。当WebAssembly作为Web标准技术引入时,JavaScript的替代品被创建出来。由于WebAssembly是浏览器可以直接执行的字节码,因此解析和编译代码的过程现在在浏览器外部。

Microsoft使用此执行路径在WebAssembly上运行.NET运行时。在浏览器中运行.NET代码的功能支持Blazor框架和自定义.NET应用程序代码。任何不依赖于框架细节的泛型.NET库在大多数情况下都可以工作。此外,Blazor还具有丰富的专用库和本机UI组件库(如适用于Blazor的Telerik UI)的生态系统。

在合理范围内,大多数.NET库都可以在浏览器中运行。例外情况包括面向浏览器上不存在的非Web平台特定功能的代码。

Blazor WebAssembly选择

使用Blazor交互式WebAssembly,选择使用.NET服务器托管应用程序可提供其他优势,例如服务器预呈现和渐进式增强。对于渐进式Web应用程序(PWA)或静态文件托管,也可以完全禁用这些功能。

启动新的Blazor WebAssembly项目时,可以通过在两个模板之间进行选择来轻松做出这些选择。

  • Blazor Web 应用 – 用于创建具有服务器预呈现和渐进式增强以及可选服务器和客户端交互模式的 Blazor 应用程序的模板。
  • Blazor 独立 WebAssembly 应用 – 此模板用于创建具有客户端呈现和交互性的 Blazor WebAssembly 应用。它不包括解决方案中的服务器项目。此模板非常适合 PWA。可以通过在安装过程中选中“渐进式 Web 应用程序”选项来添加 PWA 内容。此外,它还可用于开发具有 .NET MAUI 应用的 Blazor Hybrid
  • 适用于 Blazor 应用的 Telerik UI – 将 Telerik UI 用于 Blazor 的 Visual Studio 扩展时,包含此模板。这些扩展增强了使用适用于 Blazor 的 Telerik UI 开发 Blazor Web 应用程序的体验。

在本文中,我们将重点介绍Blazor Web应用配置。此配置是编写Web应用程序的更常用解决方案,并提供最佳的首次访问加载时间。

启动新的Blazor Web应用项目

“Blazor Web应用”对话框提供了用于生成新Blazor应用程序的多个选项。项目自定义选项包括身份验证设置、渲染模式规范、交互位置以及用于根据特定要求定制项目的各种其他可配置参数。对于Blazor交互式WebAssembly项目,我们将使用以下设置。

  • 身份验证类型:
  • 交互式渲染模式:WebAssembly
  • 交互位置:每页/组件
  • 选中“包括示例页”

每页/页”组件选项会将项目配置为使用渐进式增强。这意味着当不需要交互性时,某些页面将在静态服务器上呈现。其他页面将使用服务器预渲染和WebAssembly进行交互。通过选择此配置,服务器呈现将解决首次访问加载时间问题。对于非交互式页面,该页面将由服务器完全呈现。对于交互式WebAssembly页面,在首次加载运行时时,在页面交互之前,将显示一个完全预渲染的页面,但有很短的延迟。

该模板将使用两个解决方案搭建一个新项目,第一个是ASP.NET Core应用程序,第二个是Blazor客户端应用程序。让我们探索这两种解决方案,并了解每个文件的用途。

服务器解决方案

  • /Wwwroot——Web 标准静态资源,包括:CSS、JavaScript、JSON、图像和HTML。发布应用程序后,此文件夹中的内容始终是公开的。
  • /Components——应用程序中使用的所有非交互式组件的默认文件夹。除非另有说明,否则Blazor中的文件夹将自动确定组件的命名空间。
  • /../Layout——此文件夹中的组件是布局组件。
  • /../Layout/MainLayout.razor——应用程序的默认布局。这是应用程序最外层呈现的内容。
  • /../Layout/MainLayout.razor.css——由MainLayout组件呈现的HTML的CSS。
  • /../Pages——此文件夹中的组件具有路由指令,应用程序可以使用URL路由到该组件。
  • /../Pages/Error.razor——应用程序遇到错误时显示的一般错误页。
  • /../Pages/Home.razor——默认页面,也称为应用程序根目录。当导航到应用程序的根URL“/”时,将显示此页面。
  • /../Pages/Weather.razor——使用静态SSR的示例,此组件由服务器呈现,没有交互模式。此示例使用流式处理来优化页面加载时间。
  • /../Components/_Imports.razor——_Imports.razor文件充当所有.razor文件的全局using语句,这些文件是它的同级或子级文件。此文件的内容将附加到其中,具体取决于为项目模板选择的选项。
  • /../Components/App.razor——App.razor文件是应用程序呈现的第一个组件,包含应用程序的基本 HTML。这包括html、head和body元素。包括对静态资源的引用,例如应用程序所需的CSS、JavaScript、字体和图像。HeadOutlet和Routes组件是App组件的子组件。在此配置中,未在这些组件上指定渲染模式参数。
  • /../Components/Routes.razor——路由组件是应用程序的路由器。导航到时,组件将呈现在Routes组件中。路由组件受“身份验证模板”选项的影响。
  • /appsettings.json——json格式的应用程序设置文件。
  • /Program.cs——服务器上的应用程序入口点。此处定义了应用程序的配置。

客户解决方案

  • /../Pages/Counter.razor——Blazor交互式WebAssembly的简单示例。此示例具有带有交互式按钮的HTML,用于触发C#事件。
  • /_Imports.razor——_Imports.razor 文件充当与其同级或子级的所有.razor文件的全局using语句。此文件的内容将附加到其中,具体取决于为项目模板选择的选项。
  • /Program.cs——应用程序在客户端上的入口点。此处定义了应用程序的配置。

应用程序脚手架完成后,我们就可以启动应用程序了。应用程序将立即显示主页。导航到计数器组件时,页面将立即显示,但是,在尝试单击计数按钮时可能会注意到轻微的延迟。虽然页面是快速呈现的,但交互所需的资源仍在加载中。

这种延迟仅在第一次加载应用程序时才明显。后续的页面访问和导航不会遇到进一步的延迟。可以通过浏览器调试工具确认该行为。尝试清除应用程序数据并重新加载页面,同时观察网络流量。首次加载计数器页面时记下*.wasm文件。

验证应用程序是否正常工作后,我们就可以开始编写组件了。

为Blazor WebAssembly编写组件

Blazor应用程序的组件称为Razor组件,因为它们使用Razor语法,即C#和HTML的混合体。Razor组件通常由指令、标记和代码块组成。

指令添加了特殊功能,如路由或依赖注入。ASP.NET MVC或Razor Pages中也使用相同的指令语法。组件标记主要是HTML,由Razor增强。Razor语法允许C#与标记内联使用,并可以在UI中呈现值。

组件的逻辑写在@code块中。这是定义组件参数和数据绑定值的地方。或者,使用代码隐藏引用代码。Razor组件模型允许我们将UI分解为可管理的部分。然后,可以将组件组装成更大的UI,形成更复杂的组件和页面。

添加新组件

让我们创建一个简单的组件来显示文章标题的随机列表。由于该组件将使用WebAssembly交互模式,因此需要在Client项目的Pages文件夹中创建它。将添加一个名为ArticleListView的新.razor文件。

接下来,告诉Blazor在用户访问domain.com/articles URL时显示该ArticleListView组件。通过添加值为"/articles"@page指令来创建路由。然后向组件添加几行示例标记。我们将使用一个简单的列表来为我们需要编写的逻辑设置一个占位符。占位符标记如下所示,并显示项目的静态列表。

通过启动应用程序在浏览器中显示组件,并通过在浏览器的地址栏中输入导航到/articles

@page "/articles"
<h3>List View</h3>
<ul>
    <li>Item 1</li>
    <li>Item 1</li>
    <li>Item 1</li>
</ul>

在验证了组件的工作后,我们可以用新的页面路由更新应用程序的导航菜单。在服务器项目中,通过复制天气导航元素并将weather值替换为articles来添加articles路由。天气导航元素是标记和Blazor NavLink组件的组合。该NavLink组件是Blazor附带的简单组件,用于帮助生成导航栏。

NavLink组件的href属性设置为articles,对应于ArticleListView组件中的@page路由。NavLink里面是一个HTML模板,其中包括一个可选span的图标和文本Weather。将文本Weather更改为Articles并重新启动应用程序。该应用应在菜单中显示文章

<div class="nav-item px-3">
    <NavLink class="nav-link" href="articles">
        <span class="bi bi-list-nested-nav-menu" aria-hidden="true"></span> Articles
    </NavLink>
</div>

让我们修改组件以显示文章标题的固定列表。定义一个@code块以包含此组件的C#代码。该@code块将添加到组件的标记下方。在里面,添加一个固定的文章标题数组。然后,我们将编写一个名为GetArticles的count参数的方法,该方法采用一个count参数,并根据参数返回随机数量的文章。最后,在标记部分,我们将使用一个Razor代码块用GetArticles返回的值替换li元素。显示值的最简单方法是使用foreach循环,并在循环中写入每个值。

可以在 Telerik Blazor REPL 上查看此组件和已完成代码的示例,Telerik Blazor REPL 是一个用于创建、运行Blazor组件并与之交互的联机沙盒。通过启动应用程序并访问articles,您应该会看到与下面相同的结果。

@page "/listview"
<h3>List View</h3>

<ul>
    @foreach (var item in GetArticleTitles(5))
    {
        <li>@item</li>
    }
</ul>

@code {

    public string[] GetArticleTitles(int count) => 
    Enumerable.Range(1, count)
    .Select(index => articleTitles[Random.Shared.Next(articleTitles.Length)])
    .ToArray();

    string[] articleTitles = {
    "Mastering Asynchronous Programming in .NET",
    "Exploring the Power of LINQ in C#",
    "Building Scalable Web Applications with ASP.NET Core",
    "Deep Dive into Entity Framework: Tips and Tricks",
    "Understanding Dependency Injection in .NET",
    "Securing Your .NET Applications: Best Practices",
    "Exploring the New Features in C# 10",
    "Debugging Techniques for .NET Developers",
    "Cross-Platform Development with Xamarin.Forms",
    "Performance Optimization in .NET: A Comprehensive Guide",
    "Building RESTful APIs with ASP.NET Core",
    "Getting Started with Blazor: A WebAssembly Framework",
    "Exploring Design Patterns in .NET",
    "Containerizing .NET Applications with Docker",
    "Working with SignalR for Real-Time Communication",
    "Mastering Unit Testing in .NET",
    "Integrating Machine Learning with .NET Applications",
    "Exploring Microservices Architecture in ASP.NET Core",
    "Building a Cloud-Native .NET Application with Azure",
    "Continuous Integration and Deployment in .NET"
    };
}

 

我们将利用组件的生命周期方法,而不是直接从Razor标记调用GetArticles。使用组件生命周期方法将创建更易于推理和扩展的代码。

让我们更新现有@code块以使用OnInitialized生命周期事件。首次创建组件时,将调用该OnInitalized{Async}事件。此事件通常用于设置组件的初始状态。

对于第一次加载,我们将获得五篇文章并将它们显示在列表中。在更新的示例中,在OnInitialized过程中调用GetArticles时,添加articles字段来保存文章标题。foreach循环将更新为循环访问articles字段中的值。

至此,该组件由服务器预渲染,在初始化期间随机选择五篇文章。让我们继续改进组件,允许用户通过加载更多项目来与组件进行交互。

首先,我们将添加一个供用户交互的button。按钮的@onclick事件绑定到组件中的私有方法,该方法将10篇文章加载到articles字段中。在下面的示例中,添加了button并将其绑定到该Reload方法。此方法使用参数10进行调用GetArticles

当应用程序启动并导航到/articles时,将显示五个项目。如果我们尝试单击重新加载”按钮,则不会导致更新。即使组件逻辑正确且组件已放置在客户端项目中,我们也没有告知Blazor如何处理交互性。若要解决此问题,组件需要一个@rendermode属性。@rendermode设置为InteractiveWebAssembly,这告知Blazor使用.NET WebAssembly运行时来执行逻辑。

@rendermode InteractiveWebAssembly添加到组件后,将重新启动应用并观察预期行为。可以在下面看到此组件的示例和已完成的代码Blazor REPL。请注意,InteractiveWebAssembly是在Blazor REPL中全局设置的,因此该属性在此处不适用。

@page "/listview"
<h3>List View</h3>

<ul>
    @foreach (var item in articles)
    {
        <li>@item</li>
    }
</ul>

<button @onclick="Reload">Reload</button>

@code {
    public string[] articles = Array.Empty<string>();
    protected override Task OnInitializedAsync()
    {
        articles = GetArticleTitles(5);
        return base.OnInitializedAsync();
    }

    private void Reload()
    {
        articles = GetArticleTitles(10);
    }

    public string[] GetArticleTitles(int count) => 
    Enumerable.Range(1, count)
    .Select(index => articleTitles[Random.Shared.Next(articleTitles.Length)])
    .ToArray();

    string[] articleTitles = {
    "Mastering Asynchronous Programming in .NET",
    "Exploring the Power of LINQ in C#",
    "Building Scalable Web Applications with ASP.NET Core",
    "Deep Dive into Entity Framework: Tips and Tricks",
    "Understanding Dependency Injection in .NET",
    "Securing Your .NET Applications: Best Practices",
    "Exploring the New Features in C# 10",
    "Debugging Techniques for .NET Developers",
    "Cross-Platform Development with Xamarin.Forms",
    "Performance Optimization in .NET: A Comprehensive Guide",
    "Building RESTful APIs with ASP.NET Core",
    "Getting Started with Blazor: A WebAssembly Framework",
    "Exploring Design Patterns in .NET",
    "Containerizing .NET Applications with Docker",
    "Working with SignalR for Real-Time Communication",
    "Mastering Unit Testing in .NET",
    "Integrating Machine Learning with .NET Applications",
    "Exploring Microservices Architecture in ASP.NET Core",
    "Building a Cloud-Native .NET Application with Azure",
    "Continuous Integration and Deployment in .NET"
    };
}

 

到目前为止,该示例演示了如何使用交互式WebAssembly构建组件。在下一节中,我们将继续通过发出HTTP请求和显示来自Web终结点的数据来改进组件。

将HTTP客户端与Blazor交互式WebAssembly配合使用

将Blazor与交互式WebAssembly配合使用的组件在客户端的浏览器中执行,并且需要通过HTTP请求从服务器获取数据。此外,使用ASP.NET服务器时,组件将预呈现服务器端。将使用两种获取数据的方法,一种用于服务器,一种用于客户端。此配置是通过接口和依赖项注入完成的。

服务器设置

让我们首先使用数据服务配置服务器。数据服务将与前面示例中使用的“文章列表”相同,并表示实际应用程序中的数据库。该服务只有一个GetArticles方法,即返回随机数量的文章标题。在此版本中,TaskFromResult用于表示对数据库的异步调用或其他长时间运行的操作。

 public class ArticleService
    {
        string[] articleTitles = {
    "Mastering Asynchronous Programming in .NET",
    ... more article titles
    "Continuous Integration and Deployment in .NET"
        };

        public Task<string[]> GetArticleTitles(int count) => Task.FromResult(
            Enumerable.Range(1, count)
            .Select(index => articleTitles[Random.Shared.Next(articleTitles.Length)])
            .ToArray()
            );
    }

接下来,需要一个接口,以便可以通过依赖注入轻松更改服务实现。在Client项目中创建一个名为IArticleService的新接口。由于Server已引用Client项目,因此这两个项目都可以访问该接口。该接口定义了GetArticleTitles方法。

public interface IArticleService
{
     Task<string[]> GetArticleTitles(int count);
}

现在接口已经创建好了,需要在服务器应用程序的Program.cs中通过依赖注入对其进行注册。通过builder.Services集合声明ArticleService的一个Scoped实例来注册服务。

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddScoped<IArticleService, ArticleService>();
//... other services

var app = builder.Build();

ArticleListView组件现在能够注入服务。在ArticleListView中,可以删除示例文章数据和GetArticleTitles示例,可以删除并替换为IArticleService。由于在服务中GetArticles是异步的,因此我们将使用生命周期方法的OnInitializedAsync版本。通过将void返回类型替换为async Task,该Reload方法还更新为异步。ArticleListView的完整代码如下所示。

 
@page "/articles"
@rendermode InteractiveWebAssembly
@inject IArticleService service
<h3>List View</h3>

<ul>

    @foreach (var item in articles)
    {
        <li>@item</li>
    }

</ul>

<button @onclick="Reload">Reload</button>

@code {
    public string[] articles = [];
    protected override async Task OnInitializedAsync()
    {
        articles = await service.GetArticleTitles(5);
    }

    private async Task Reload()
    {
        articles = await service.GetArticleTitles(10);
    }

}

应用程序可以成功启动,但导航到该/articles页面将显示错误。浏览器控制台中显示消息没有注册服务”ProjectName.Client.IArticleService“类型。发生此错误的原因是组件已成功预呈现,但是当客户端尝试执行相同的组件代码时,它无法解析IArticleService的服务。若要完成客户端逻辑,我们需要公开Web API终结点并使用HttpClient

最小API

若要将数据从服务器公开到客户端,应用程序将需要一个Web API终结点。Web API 终结点是使用最小API在服务器项目中创建的。最少的API以最少的代码和配置实现功能齐全的REST端点。使用最小API,IArticleService可用于从其GetArticleTitles方法提供JSON数据。

Server项目的Program.cs文件中,添加了该MapGet方法。使用MapGet我们将GET请求分配给所需的终端节点——在本例中,我们将使用/values。由于GetArticleTitles需要一个参数,我们将映射一个count值,该值通过GET请求"/values/{count}传递到端点。

接下来,在MapGet中,IArticleService使用[FromServices]属性进行解析,并调用GetArticleTitles方法。这行代码解析了我们服务的实例,并在请求/values时返回包含文章标题的JSON响应。

app.MapGet("/values/{count}", 
    async (int count, [FromServices] IArticleService articles) =>
     await articles.GetArticleTitles(count)
     );

启动应用程序并直接访问 URL,以在浏览器中查看JSON响应。在浏览器的地址栏中,测试https://localhost:{port}/values/5将返回包含五个项目的JSON响应。

https://localhost:7041/values/5
[
    "Exploring the New Features in C# 10",
    "Building RESTful APIs with ASP.NET Core",
    "Building RESTful APIs with ASP.NET Core",
    "Performance Optimization in .NET: A Comprehensive Guide",
    "Exploring Design Patterns in .NET"
]

Server项目现已完成,我们可以完成Client项目的接线。

客户端设置

连接到web API端点需要在Client项目中使用HttpClient。配置客户端项目需要添加基于HTTP的IArticleService服务实现,并使用依赖项注入注册HttpClient。

首先,在客户端项目中创建名为ArticleHttpService的服务。服务通过该GetArticles方法实现IArticleServiceHttpClient的实例被注入到使用构造函数注入中的ArticleHttpService。然后,该GetArticleTitles方法用于调用/values Web终结点。使用HttpClient GET请求中的GetFromJsonAsync<string[]>方法,并将JSON响应序列化为字符串值数组。最后,该方法返回序列化数组。完成的服务显示在下面的代码中。

public class HttpArticleService(HttpClient http) : IArticleService
{
    public Task<string[]> GetArticleTitles(int count) =>
    http.GetFromJsonAsync<string[]>($"values/{count}")!;
}

创建HttpArticleService后,需要在Client项目的Program.cs文件中配置依赖项注入。通过builder.Services集合声明HttpClientHttpArticleServiceScoped实例来注册服务。注册HttpClient时,将使用应用程序的基址配置BaseAddress属性。

builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
builder.Services.AddScoped<IArticleService, HttpArticleService>();

现在可以启动应用程序,并且ArticleHttpService将不再遇到错误,但是随机数据会明显刷新。当Blazor在服务器上预呈现组件时,它将执行组件的整个生命周期。此外,Blazor WebAssembly客户端将在浏览器中初始化组件。

这两个初始化周期将导致生成两组数据,一组在服务器上,另一组在客户端上。为了修正双重初始化,我们将利用名为PersistentComponentState的Blazor功能。

持久化预渲染状态

当组件被预渲染时,它将完成其组件生命周期。在浏览器中加载时,组件将重新初始化,重复生命周期过程。该PersistentComponentState服务允许我们进入应用程序生命周期,并利用它来持久化组件的状态。

当通过RegisterOnPersisting订阅回调时,状态将使用该PersistAsJson方法进行编码并嵌入到呈现组件的HTML中。可以使用该TryTakeFromJson方法检索嵌入的状态。

让我们修改ArticleListView以实现持久状态并消除对GetArticleTitles的其他调用。首先,将该PersistentComponentState方法作为ApplicationState注入到组件中。然后创建一个PersistingComponentStateSubscription实例来保存回调委托方法。

...
@inject PersistentComponentState ApplicationState
...
@code {  
    private PersistingComponentStateSubscription persistingSubscription;
}

在该OnInitalizedAsync方法中,该ApplicationState实例使用RegisterOnPersisting注册回调。该PersistArticles方法将添加到组件中,并用于调用PersistAsJson。当PersistAsJson被称为键时,并将数据传递给方法,并与组件的输出一起呈现。

protected override async Task OnInitializedAsync()
{
    // Subscribe to application life-cycle, register callback to persist state
    persistingSubscription = ApplicationState.RegisterOnPersisting(PersistArticles);

   ...
}

private Task PersistArticles()
{
    // Save state
    ApplicationState.PersistAsJson(nameof(articles), articles);

    return Task.CompletedTask;
}

在预渲染期间保存状态后,需要更新组件以检索状态。在该OnInitializedAsync方法中,调用TryTakeFromJson,如果不存在状态,则组件将调用GetArticleTitles。当TryTakeFromJson具有状态时,articles数组将从嵌入状态填充。

protected override async Task OnInitializedAsync()
{
    // Subscribe to application life-cycle, register callback to persist state
    persistingSubscription = ApplicationState.RegisterOnPersisting(PersistArticles);

    if (!ApplicationState.TryTakeFromJson<string[]>(nameof(articles), out var restoredArticles))
    {
        // State is not available
        articles = await service.GetArticleTitles(5);
    }
    else
    {
        // State is available
        articles = restoredArticles!;
    }
}

最后,IDisposable接口由组件实现,以正确处理PersistentComponentState服务。

void IDisposable.Dispose() => persistingSubscription.Dispose();

现在,当我们启动应用程序并导航到/articles页面时,列表将显示五个项目。该组件将保留最初的五个项目,并且不再第二次刷新这些项目。

完成的项目可以从 GitHub 下载。

结论

本文探讨了.NET 8和Blazor WebAssembly中引入的最新功能。我们了解了如何将Blazor WebAssembly与.NET服务器配合使用,从而实现预呈现,从而允许应用在利用客户端交互性的同时快速呈现。引入预渲染需要额外的代码来维护状态。使用PersistentComponentState,我们订阅了应用程序生命周期内的事件,以实现预渲染,而无需不必要地重新加载数据。使用WebAssembly构建交互式Blazor应用是具有完整全栈开发人员体验的.NET开发人员的JavaScript替代方法。

https://www.telerik.com/blogs/building-interactive-blazor-apps-webassembly

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值