理论上,使用静态渲染模式发布 Blazor 表单应该可行。 但是,它不是由 Blazor 处理,而是作为 MVC 表单处理,发布到
/
。
根据客户的要求,我使用静态渲染模式。
我错过了什么?
<Router />
?<script src="_framework/blazor.web.js"></script>
假设:
可以通过多种方式在 MVC 页面上呈现 Blazor 组件:
RenderComponentAsync
的示例: @(await Html.RenderComponentAsync<SubscribeToNewsletterForm>(RenderMode.Static, new
{
BtnLabel = "Subscribe"
}))
<component type="@(typeof(SubscribeToNewsletterForm))" render-mode="Static" />
我已经尝试过:
<script src="_framework/blazor.web.js"></script>
包括 BlazorFrameworkFiles
无济于事。最后,我使用静态渲染模式创建了完整的 Blazor SPA,并将 MVC 移动到不同的路线上运行。
Blazor SPA 正确处理表单,因此我的假设是 Blazor
<Router />
需要干预表单发布和导航。
我的假设正确吗? 如果是这样,在 MVC 页面上使用 Blazor 组件仅限于渲染?
具有以下形式的 Blazor 组件:
<EditForm Model="@SubscriptionModel" OnValidSubmit="@HandleSubscriptionForm" FormName="SubscriptionModel">
<FluentValidationValidator/>
<div class="input-group">
<InputText type="email" class="form-control email-input" required
placeholder="Enter your email" aria-label="Enter your email" @bind-Value="SubscriptionModel.Email"/>
<button class="btn btn-primary subscribe-button" type="submit">@BtnLabel</button>
</div>
<ValidationSummary/>
</EditForm>
@code {
[Parameter]
public string? BtnLabel { get; set; } = "Join";
[SupplyParameterFromForm]
public SubscribeToNewsletterRequest? SubscriptionModel { get; set; }
protected override void OnInitialized()
{
SubscriptionModel ??= new SubscribeToNewsletterRequest();
}
private async Task HandleSubscriptionForm()
{
Console.WriteLine("Handling subscription form...");
...
}
public record SubscribeToNewsletterRequest
{
public string Email { get; set; }
}
}
您需要非常小心地谈论 Blazor Server 的服务器端渲染,因为组件可能会在两个位置之一渲染。
静态服务器端渲染 [SSSR] 是在
HttpRequest
上下文中渲染组件的位置。除了单例服务之外的所有内容都是在上下文中创建和销毁的。这是经典的老式 MVC、Razor 和 ASP。
活动服务器端渲染 [ASSR] 是指在 Blazor 中心的集线器会话上下文中渲染浏览器上的 SPA 会话。
由于您提供的代码不是有效的 MRE [最小可重现示例],我将使用 MS 文档中的 Starship 示例代码。请参阅 https://learn.microsoft.com/en-us/aspnet/core/blazor/forms/?view=aspnetcore-8.0
在
App
中设置路由组件如下
<Routes />
下面的页面将在 HttpRequest Context 中渲染 ASSR。该表单会将页面发送回服务器,并由
Starship
表单进行处理。在 Id 中输入超过 10 个字母,然后按 Tab 键退出输入,但没有任何反应。没有交互性,因为没有定义。仅当您将表单发送回服务器时才会进行验证。
尝试使
InputText
交互以尝试显示验证消息。你会得到一个错误。 InputText
依赖于 EditForm
的级联参数,而静态渲染 EditForm
时这些参数不存在。它们存在于渲染 EditForm
的 HttpRequest Context中。但是
InputText
存在于 Hub 会话上下文中。
@page "/starship"
@using System.ComponentModel.DataAnnotations
@inject ILogger<Starship> Logger
<EditForm Model="@Model" OnValidSubmit="@Submit" FormName="Starship">
<DataAnnotationsValidator />
<ValidationSummary />
<label>
Identifier:
<InputText @bind-Value="Model!.Id" />
</label>
<button type="submit">Submit</button>
</EditForm>
@code {
[SupplyParameterFromForm]
public Starship? Model { get; set; }
protected override void OnInitialized() => Model ??= new();
private void Submit()
{
Logger.LogInformation("Id = {Id}", Model?.Id);
}
public class Starship
{
[Required]
[StringLength(10, ErrorMessage = "Id is too long.")]
public string? Id { get; set; }
}
}
为整个表单添加交互性,现在您可以在页面中获得交互性的内容。在表单验证中输入太多字母并按 Tab 键离开触发器,您会立即收到一条验证消息。
@page "/starship"
@using System.ComponentModel.DataAnnotations
@inject ILogger<Starship> Logger
@rendermode InteractiveServer
<EditForm Model="@Model" OnValidSubmit="@Submit" FormName="Starship">
在这种情况下,路由器仍然在 SSSR 模式下运行,因此每个页面都会发送回服务器,最初静态渲染,然后根据页面/组件的渲染设置进行渲染。
如果您设置:
<Routes @rendermode="InteractiveServer" />
然后你就可以进行全局设置了。这与旧的 Blazor Server 模式相同。路由器不会在 SPA 内呈现,并且不会回发到服务器。
个人评论
如果这是从现有服务器端渲染应用程序的迁移,那么以混合模式运行来进行增量迁移就可以了。如果这是一个新的应用程序,那就没有意义了。您将创造额外的复杂性而没有任何好处。额外的复杂性将会带来巨大的成本。