首页 程序笔记 Blazor ServerPrerendered模式OnInitialized{Async}执行两次

Blazor ServerPrerendered模式OnInitialized{Async}执行两次

创建Blazor应用,刷新页面调试时发现OnInitialized会执行两次。 这里需要注意,进入这个站点的第一个页面的OnInitialized会被执行两次,例如我在浏览器输入URL进去了A页面,那么A页面的OnInitialized会执行两次。然后我通过A页面上的Link进入B页面,B页面的OnInitialized只会执行一次。

OnInitialized执行两次的原因

查看微软Blazor文档作了如下解释:

预呈现后的有状态重新连接

在 Blazor Server 应用中,当 RenderMode 为 ServerPrerendered 时,组件最初作为页面的一部分静态呈现。 浏览器重新建立与服务器的 SignalR 连接后,将再次呈现组件,并且该组件为交互式。 如果存在用于初始化组件的 OnInitialized{Async} 生命周期方法,则该方法执行两次:

在静态预呈现组件时执行一次。
在建立服务器连接后执行一次。

在最终呈现组件时,这可能导致 UI 中显示的数据发生明显变化。 若要避免在 Blazor Server 应用中出现此双重呈现行为,请传递一个标识符以在预呈现期间缓存状态并在预呈现后检索状态。

一开始看这个文档有点难以理解,我们用通俗的话来解释一下:

预呈现ServerPrerendered是一个网页的所有元素都在服务器上编译并将静态 HTML 提供给客户端的过程。 

ServerPrerendered模式下第一次调用OnInitialized发生再服务器上,服务器必须完成创建静态 html 网站的所有工作,并将内容发送给用户后,第二个 OnInitialized开始执行。

ServerPrerendered用于帮助 SPA(单页应用程序)改进其 SEO(搜索引擎优化)。 另一个好处是网站加载速度似乎更快。这一切都发生在非常短的时间内,大多数最终用户是无法察觉的。

直观的来看,如果使用ServerPrerendered模式,你右键网页查看源文件那么它是输出服务端渲染的内容的。如果使用Server模式,那么右键查看源文件没有实际内容。

如何避免OnInitialized执行两次

将render-mode改为server(SEO不友好)

根据文档的提示,我们可以通过修改_Host.cshtml里的render-mode="Server"来避免OnInitialized执行两次。

<component type="typeof(App)" render-mode="ServerPrerendered" />
// 修改为
<component type="typeof(App)" render-mode="Server" />

这样修改后刷新页面只会执行一次OnInitialized。但是,如果我们对SEO搜索引擎优化有要求,那么这样做显然是不行的。

持久保存预呈现组件的状态

之前我一直无法理解“传递一个标识符以在预呈现期间缓存状态并在预呈现后检索状态”,后来看到了persist-component-state提供的解决方案。它的用法也比较简单,先在_Host.razor中添加标签<persist-component-state />

<body>
    <component type="typeof(App)" render-mode="ServerPrerendered" />
    ...
    <persist-component-state />
</body>

然后page页面的示例代码是这样的:

@implements IDisposable
@inject PersistentComponentState ApplicationState

<h1>Hello, world!</h1>
<p>Status: @Status</p>

@code {
    public string? Status { get; set; } = "loading";
    private PersistingComponentStateSubscription persistingSubscription;

    protected override async Task OnInitializedAsync()
    {
        persistingSubscription = 
            ApplicationState.RegisterOnPersisting(PersistData);

        if (!ApplicationState.TryTakeFromJson<string>(
            "Status", out var restored))
        {
            Status = await GetStatus();
        }
        else
        {
            Status = restored!;
        }
    }

    private async Task<string> GetStatus()
    {
        await Task.Delay(3000);
        return "loaded";
    }

    private Task PersistData()
    {
        ApplicationState.PersistAsJson("Status", Status);
        return Task.CompletedTask;
    }

    void IDisposable.Dispose()
    {
        persistingSubscription.Dispose();
    }
}

示例代码里GetStatus方法模拟需要花费时间的查询,所以故意延迟3秒返回结果。

这样刷新页面时,实际执行了两次OnInitializedAsync,第一次在服务端执行OnInitializedAsync时调用GetStatus查询并缓存了Status,第二次执行OnInitializedAsync时直接从缓存拿到了Status,这样可以避免第二次重复查询浪费性能。这里不需要担心时效性问题,这个缓存范围仅在这个请求,请注意实现了IDisposable接口,会Dispose掉。再次刷新页面时还会调用GetStatus查询并缓存Status,第二次再直接从缓存里拿Status。如果从别的页面跳转过来,只会执行一次OnInitializedAsync并且执行到GetStatus。

用户体验上来看,第一次打开这个页面,白屏loading了3秒,然后输出页面,页面上显示的是Status: loaded。 也许会有人觉得奇怪,那还要loading状态做什么?

是这样的,如果用户先打开了另外一个页面,然后那个页面上有一个Link到上面示例代码的页面,那么点Link过来的时候,页面不需要白屏加载,而是直接先显示Status: loading, 然后等3秒后变成Status: loaded。 而且OnInitializedAsync只执行了一次。

如果改成render-mode="Server"后,用户体验是这样的:

页面不会白屏等待(不会Delay等待3秒),而是直接输出Status: loading,然后执行OnInitializedAsync等待3秒得到Status后页面变成Status:loaded。右键查看网页源文件的话没有实际输出内容(SEO不友好)。

下面两个图是ServerPrerendered和Server两种模式下查看网页源文件的区别,大家可以对比一下:

以上是作者做了很多调试后得到的一些结果,希望对大家理解Blazor的ServerPrerendered和Server的区别有所帮助。如果有什么错误或者更好的建议,请留言分享。

3

站心网

创建Blazor应用,刷新页面调试时发现OnInitialized会执行两次。 这里需要注意,进入这个站点的第一个页面的..

为您推荐

Blazor 与传统 ASP.NET MVC 的对比

Blazor 和传统 ASP.NET MVC 是两种不同的Web开发框架,分别针对现代前端开发需求和传统的服务端渲染需求。以下从多个维度对两者进行对比:1. 架构和工作方式Blazor基于组件的开发方式,采用现代化前端框架的思想,代..

.NET9 Blazor有哪些更新?

.NET 9 在 Blazor 中引入了多项更新,增强了开发体验和应用性能。以下是主要更新内容:1. 新的 Blazor 混合应用模板.NET 9 引入了一个支持 .NET MAUI 和 Blazor Web 客户端的混合应用模板。开发者可以利用该模板在共..

SQL Server EF使用Sequence全局自增ID

在使用 Entity Framework (EF) 时,如果需要在 SQL Server 中实现一个 全局自增 ID,可以通过以下方法来实现。全局自增 ID 的需求通常是为了在多表之间实现唯一性递增 ID。实现方式 1:使用 SQL Server 的 SequenceS..

SQL Server用UUID做主键性能问题和解决方案

在 SQL Server 中使用 UUID(全称:Universally Unique Identifier) 作为主键确实可能带来一些性能问题,特别是在大型数据库和高写入负载的场景下。以下是一些关键的性能挑战及其原因:1. 无序插入导致索引碎片化UU..

用Blazor开发App应用可行吗?

使用 Blazor 开发 App 应用是可行的,并且已成为跨平台应用开发的一种强大选择,特别适合在 Web、移动端(iOS、Android) 和 桌面端 上创建应用。Blazor 是一个支持使用 C# 和 .NET 的框架,开发者可以编写一套代码..

前端开发有必要学习Blazor吗?

前端开发者是否需要学习 Blazor 取决于你的技术栈、职业目标和项目需求。Blazor 是一个由 .NET 支持的框架,允许开发者使用 C# 进行前端开发,这对专注于 JavaScript 的传统前端开发者而言可能具有不同的吸引力和适..

js使用IntersectionObserver实现锚点在当前页面视口时导读高亮

在 JavaScript 中可以通过监听页面滚动事件,检查每个锚点的位置,并根据当前滚动位置高亮相应的导航项,从而实现页面内锚点链接的导读高亮效果。交叉观察器 API(Intersection Observer API)提供了一种异步检测目..

修改VisualSVN Server地址为ip地址,修改svn服务端地址为ip或者域名地址的方法

svn服务端搭建成功之后,地址太长很麻烦,想搞一个服务器专门做svn服务端,修改svn地址为ip地址无奈网上教程不靠谱,于是自己研究了下1.修改VisualSVN 的地址2修改地址并保存很多人不成功就在这里,点击确认之后复制..

Blazor的N种渲染模式原理和常见问题说明

我们从下面这幅图开始,下图显示了三种渲染模式,分别称之为静态SSR、交互式SSR(即之前的BlazorServer)、交互式CSR(即之前的BlazorWasm)。还有一种渲染模式BlazorHybrid,稍后说。一、先浅层理解一个图例静态SSR:经..

Angular UT 模拟执行setTimeout

在 Angular 单元测试中,我们经常需要模拟异步操作,比如 setTimeout。提高测试速度: 真实环境下的 setTimeout 会阻塞测试,导致测试运行时间过长。确保测试的可靠性: 模拟 setTimeout 可以让我们更好地控制异步操..

数据库SQL Server2014和SQL Server2019的区别和如何选择?

SQL Server 2014和SQL Server 2019是微软公司发布的两个版本的数据库管理系统,它们在性能、安全性以及可扩展性等方面各有特点。在选择这两个数据库版本时,需要根据系统需求、预算状况以及技术团队的熟悉程度等因素..

.NET Blazor 2024年发展趋势

Blazor是微软推出的一个开源且免费的框架,用于使用C#和HTML构建Web应用。这种技术允许开发者利用现有的.NET技能和库来创建交互式Web UI,从而缩短学习曲线和开发时间。随着技术的不断进步和企业对Blazor日益增长的..

Blazor获取Url路由参数的方法

这里整理了两种获取参数值的方法: 通过NavigationManager服务获取参数值和配置路由参数获取参数值。在Blazor Server和WebAssembly中,可以通过注入 NavigationManager服务获取Uri转化为Uri对象得到Query. 然后使用H..

ASP.NET Core Blazor EditForm内置表单验证显示ValidationMessage

Blazor 框架支持表单并提供内置的输入组件:绑定到使用数据注释的模型的 EditForm 组件内置输入组件我们可以把Model绑定到EditForm的Model属性,然后使用Model属性的数据注释验证表单。启用数据注释验证需要 DataAnn..

Blazor NavigateTo报错Microsoft.AspNetCore.Components.NavigationException:“Exception_WasThrown”

使用Blazor,在OnInitialized里执行NavigationManager.NavigateTo("/")的时候报错了:Microsoft.AspNetCore.Components.NavigationException:“Exception_WasThrown”网上看到说这个问题只出现在render-mo..

Blazor的5种render-mode的区别

Blazor 是一个基于 .NET 平台的 Web 应用程序开发框架,它支持多种渲染模式,包括:Server:在服务器端执行应用程序逻辑和 UI 渲染,然后通过 SignalR 技术将 UI 更新推送到客户端。这种模式适合于需要与后端服务器..

Blazor使用内存中状态容器服务保存和验证登陆状态

想用Blazor做一个简单的登录验证。模式是render-mode="ServerPrerendered"。在登录页面登录成功后需要保存类似.NET MVC网站的服务端session的状态。网上一些简单的做法是登录成功后把用户信息存在LocalStorage或者Se..

.NET MVC ViewBag ViewData Mmodel怎么选择?

在.NET MVC中,有三种不同的方式可以在控制器(Controller)和视图(View)之间传递数据,分别是ViewBag、ViewData和Model。ViewBag:ViewBag是一个动态属性(dynamic property),它允许在控制器中传递数据到视图中..

echars k线图tooltip formatter没有执行

使用echars生成k线图时,参考官网的示例发现无法修改tooltip的内容,经过研究发现官网示例代码是不正确的。以名为[K 线图刷选]的K线图为例,因为它的示例里有tooltip formatter的实现代码,但是实际上是没有执行的。..

.NET的Razor和Blazor有什么区别和联系?

什么是RazorRazor 是一个用于构建动态 Web 页面的标记语言和引擎,用来创建动态网页。它允许在 HTML 中嵌入 C# 代码,使开发人员能够更方便地生成动态内容。Razor 可以与 ASP.NET Web Forms、ASP.NET MVC 和 ASP.NET..

发表回复

返回顶部