PAYATHON 2026

如何在 Blazor 中校验组件参数并理解 SetParametersAsync 的执行流程?

数据阿明

通常可以在 OnParametersSet 中校验组件参数,[Parameter] 属性保持为自动属性。需要在参数赋值前拒绝非法值,或必须在初始化逻辑执行前完成校验时,再重写 SetParametersAsync。

如何校验字符串长度和数值范围?

下面的组件示例要求 Title 不能为空且长度不超过 100,Count 至少为 1。这些数值仅用于演示,应替换成实际业务约束。

@using System
@using Microsoft.AspNetCore.Components

<p>@Title:@Count</p>

@code {
    [Parameter]
    public string? Title { get; set; }

    [Parameter]
    public int Count { get; set; } = 1;

    protected override void OnParametersSet()
    {
        if (string.IsNullOrWhiteSpace(Title))
        {
            throw new ArgumentException(
                "Title 不能为空。", nameof(Title));
        }

        if (Title.Length > 100)
        {
            throw new ArgumentException(
                "Title 长度不能超过 100。", nameof(Title));
        }

        if (Count < 1)
        {
            throw new ArgumentOutOfRangeException(
                nameof(Count), Count, "Count 必须至少为 1。");
        }
    }
}

进入 OnParametersSet 时,本轮传入的参数已经赋给组件属性,可以直接读取,也可以检查多个参数之间的约束。使用自动属性可以避免 setter 中的副作用干扰参数传递和渲染流程。组件参数文档

这里的异常适用于调用方传入了组件不支持的配置。如果非法值来自用户正在编辑的表单,应保存错误状态并展示提示,或使用表单验证机制,不要把正常的输入错误都处理成组件异常。

SetParametersAsync 在赋值前还是赋值后执行?

SetParametersAsync 是接收一批参数的入口。默认实现先调用 parameters.SetParameterProperties(this),然后进入初始化和参数生命周期逻辑。

以问题所引用的 .NET 9 实现为例,主要调用顺序如下:

SetParametersAsync(parameters)
  → parameters.SetParameterProperties(this)
  → 首次调用时执行 OnInitialized / OnInitializedAsync
  → OnParametersSet
  → OnParametersSetAsync
  → 发起相应的渲染请求

如果异步生命周期方法尚未完成,中间也可能发生渲染,并不是只有最后一步才会渲染。具体流程可参照 ComponentBase 的 .NET 9 源码。

在自己的重写方法中:

  • 调用 SetParameterProperties 之前,本轮参数还没有由这次调用写入组件属性,应从 parameters 读取传入值。
  • 调用之后,组件属性已经包含本轮传入值,可以直接校验属性。
  • OnParametersSet 发生在首次初始化之后。如果 OnInitialized 会使用这些参数,且必须在使用前校验,应把检查提前到 SetParametersAsync。

调用 OnParametersSet 并不代表参数值一定发生了变化。若业务需要检测变化,应自行保存并比较上次的值。

如何在赋值前校验某个参数?

可以先用 ParameterView.TryGetValue 检查本轮传入的值,再交给基类完成赋值和生命周期处理:

public override Task SetParametersAsync(ParameterView parameters)
{
    if (parameters.TryGetValue<string?>(nameof(Title), out var title))
    {
        if (string.IsNullOrWhiteSpace(title) || title.Length > 100)
        {
            throw new ArgumentException(
                "Title 不能为空,且长度不能超过 100。",
                nameof(Title));
        }
    }

    return base.SetParametersAsync(parameters);
}

这个示例只检查本轮包含的 Title。未包含的参数会保留组件属性原有的值,不会自动清空。如果还要检查最终状态是否完整,或检查多个参数的组合关系,仍可在 OnParametersSet 中处理。SetParametersAsync 文档

原代码中的两处调用能否省略?

省略 SetParameterProperties(this)

原代码传给基类的是 ParameterView.Empty。如果同时省略手动赋值,基类就没有本轮参数可供写入,属性会保留之前的值,或首次调用前的默认值。

如果不需要手动赋值,直接使用下面的调用即可:

return base.SetParametersAsync(parameters);

如果已经手动执行了 parameters.SetParameterProperties(this),再传 ParameterView.Empty,则表示参数已经处理完,只让基类继续执行生命周期和渲染逻辑。空的 ParameterView 不会重置现有属性。生命周期文档

省略基类调用

仅调用 SetParameterProperties 只完成属性赋值,不会自动执行 ComponentBase.SetParametersAsync 中的初始化、参数生命周期及相关渲染调度。普通组件应保留基类调用。

还要区分“省略调用”和“省略 return”:当前方法没有声明 async,必须返回 Task。保留 return base.SetParametersAsync(...),或改成 async Task 并使用 await base.SetParametersAsync(...),都可以正确传递完成状态和异常。ComponentBase 源码

使用时还有哪些注意事项?

  • 不要为了修正参数而在组件内部反复改写 [Parameter] 属性。需要规范化后的值时,使用单独的字段或计算属性。
  • [EditorRequired] 提供编辑或构建阶段的提示,不保证运行时值有效,也不能替代长度和范围校验。组件参数文档
  • 示例中的 Title.Length 计算 UTF-16 代码单元数量。如果业务要求按用户看到的字符计数,需要另行确定计数规则。

备注:内容仅供参考。