Blazor Server中_Layout引用<partial/>加载弹窗遇_Host相关报错
Blazor Server 加载完成后显示绑定模型弹窗的问题
我尝试在Blazor Server网站加载完成后,显示一个绑定模型数据的警告弹窗,但遇到了运行错误。以下是我的实现步骤:
1. 定义AlertModal模型类
public class AlertModal { [Key] public int AlertId { get; set; } public string Image { get; set; } [Required(ErrorMessage = "This is a requierd field")] public string TextPar { get; set; } public string TextPar1 { get; set; } public string TextPar2 { get; set; } [Required(ErrorMessage = "This is a requierd field")] public bool Show { get; set; } }
2. 创建分部视图的PageModel
public class _InfoPartialModel : PageModel { public AlertModal AlertModal { get; set; } public void OnGet() { AlertModal = new AlertModal() { TextPar = "This is a test", Show = true }; } }
3. 编写分部视图页面
@page @model Tjoba.Pages.Shared._InfoPartialModel @{} @if (Model.AlertModal.Show) { <div class="modal fade " id="IndexModal" role="dialog" tabindex="-1" aria-hidden="true"> <div class="modal-dialog modal-dialog-centered" role="document"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title text-black">@Model.AlertModal.TextPar </h5> <button type="button" data-bs-dismiss="modal" aria-hidden="true">x</button> <button type="button" class="close" data-dismiss="modal" aria-label="Close"> <span aria-hidden="true">×</span> </button> </div> <div class="modal-body"> <div class="row"> <img src="/images/Vacation_volleyball.jpeg" class=" col-12 p-0 m-0 mx-auto " style="transform:none" /> </div> </div> <div class="modal-footer"> <button class="btn btn-secondary" value="1" data-bs-dismiss="modal">Sluiten</button> </div> </div> </div> </div> <script> $(document).ready(function () { setTimeout(function () { $("#IndexModal").modal('show'); }, 4000); }); </script> }
4. 在_Layout.cshtml中引用分部视图
<partial name="_InfoPartial" model="Model.AlertModal" />
出现的错误
启动网站时抛出异常:
An unhandled exception occurred while processing the request.
RuntimeBinderException: 'Tjoba.Pages.Pages__Host' does not contain a definition for 'AlertModal'
我的_Host.cshtml内容如下:
@page "/" @namespace Tjoba.Pages @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers @{ Layout = "_Layout"; } <component type="typeof(App)" render-mode="ServerPrerendered" />
疑问
该错误为何与_Host文件相关?我哪里操作出错了?
问题分析与解决方案
错误原因
错误关联_Host文件的核心原因:_Host.cshtml设置了Layout = "_Layout";,所以_Layout.cshtml的渲染上下文是_Host.cshtml对应的PageModel(即Pages__Host)。你在_Layout.cshtml中尝试传递Model.AlertModal给分部视图,但_Host.cshtml根本没有定义AlertModal属性,运行时找不到这个成员,因此抛出绑定异常。
操作中的错误点
- 错误将带路由的Razor页面作为分部视图引用:你给
_InfoPartial.cshtml加了@page指令,这会让它变成一个独立的路由页面,而非普通分部视图,不能直接用<partial>标签引用。 - 模型传递上下文错误:即使是普通分部视图,
_Layout.cshtml中的Model指向的是当前使用布局的页面的Model(这里就是_Host.cshtml的Model),但_Host.cshtml没有定义AlertModal,自然会报错。
修正方案
方案一:改为普通分部视图(适配Razor页面布局)
- 修改分部视图:删除
_InfoPartial.cshtml中的@page指令,调整模型直接绑定AlertModal:
@model Tjoba.Models.AlertModal @if (Model.Show) { <div class="modal fade " id="IndexModal" role="dialog" tabindex="-1" aria-hidden="true"> <div class="modal-dialog modal-dialog-centered" role="document"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title text-black">@Model.TextPar </h5> <button type="button" data-bs-dismiss="modal" aria-hidden="true">x</button> <button type="button" class="close" data-dismiss="modal" aria-label="Close"> <span aria-hidden="true">×</span> </button> </div> <div class="modal-body"> <div class="row"> <img src="/images/Vacation_volleyball.jpeg" class=" col-12 p-0 m-0 mx-auto " style="transform:none" /> </div> </div> <div class="modal-footer"> <button class="btn btn-secondary" value="1" data-bs-dismiss="modal">Sluiten</button> </div> </div> </div> </div> <script> $(document).ready(function () { setTimeout(function () { $("#IndexModal").modal('show'); }, 4000); }); </script> }
- 删除多余的PageModel:删掉
_InfoPartialModel.cs文件,普通分部视图不需要独立的PageModel。 - 给_Host添加Model并初始化数据:
- 创建
HostModel.cs:public class HostModel : PageModel { public AlertModal AlertModal { get; set; } public void OnGet() { AlertModal = new AlertModal() { TextPar = "This is a test", Show = true }; } } - 修改
_Host.cshtml引用该Model:@page "/" @namespace Tjoba.Pages @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers @model Tjoba.Pages.HostModel @{ Layout = "_Layout"; } <component type="typeof(App)" render-mode="ServerPrerendered" />
- 创建
- 修正_Layout中的分部视图引用:保持之前的代码即可,现在
Model.AlertModal就能从HostModel中获取到数据。
方案二:使用Blazor组件实现(更推荐,贴合Blazor生态)
Blazor Server优先使用Blazor组件而非Razor页面分部视图,避免上下文混淆:
- 创建AlertModal Blazor组件:
@inject IJSRuntime JSRuntime @model Tjoba.Models.AlertModal @if (Model.Show) { <div class="modal fade " id="IndexModal" role="dialog" tabindex="-1" aria-hidden="true"> <div class="modal-dialog modal-dialog-centered" role="document"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title text-black">@Model.TextPar </h5> <button type="button" data-bs-dismiss="modal" aria-hidden="true">x</button> <button type="button" class="close" data-dismiss="modal" aria-label="Close"> <span aria-hidden="true">×</span> </button> </div> <div class="modal-body"> <div class="row"> <img src="/images/Vacation_volleyball.jpeg" class=" col-12 p-0 m-0 mx-auto " style="transform:none" /> </div> </div> <div class="modal-footer"> <button class="btn btn-secondary" value="1" data-bs-dismiss="modal">Sluiten</button> </div> </div> </div> </div> } @code { protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender && Model.Show) { await Task.Delay(4000); await JSRuntime.InvokeVoidAsync("$('#IndexModal').modal('show')"); } } }
- 在Blazor组件中引用:
比如在MainLayout.razor中添加引用,这样所有页面加载后都会显示弹窗:
@inherits LayoutComponentBase <div class="page"> <div class="sidebar"> <NavMenu /> </div> <main> <div class="top-row px-4"> <a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a> </div> <article class="content px-4"> @Body </article> </main> </div> <AlertModal Model="@new AlertModal { TextPar = "This is a test", Show = true }" />
这种方式使用Blazor的生命周期方法OnAfterRenderAsync触发弹窗,通过IJSRuntime调用JS,更符合Blazor Server的开发规范,也避免了Razor页面和Blazor组件混合的上下文问题。
内容的提问来源于stack exchange,提问作者Gerald
相关产品推荐
相关产品推荐

