You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Blazor Server .NET 8中Blazored.FluentValidation空引用异常求助

Blazor Server(.NET 8)中Blazored.FluentValidation空引用异常排查与解决

在基于.NET 8的Blazor Server登录功能实现中,使用Blazored.FluentValidation时触发空引用异常,即便遵循官方文档使用IncludeAllRuleSets()包含所有规则集,问题仍未解决。以下是问题相关代码、原因分析及解决方案建议:

相关代码

登录组件代码

<EditForm class="needs-validation" Model="@Input" OnValidSubmit="@SubmitAsync" FormName="login" novalidate>
<FluentValidationValidator @ref="@_fluentValidationValidator" />
<DataAnnotationsValidator />

<AuthInput Id="email" ErrorFeedback="" Label="Email Address"
           TextFieldType="TextFieldType.EmailAddress"
           @bind-Value="Input.Email" PlaceHolder="Email Address here"
           ValidationFor="@(() => Input.Email)" />

<AuthInput Id="password" ErrorFeedback="" Label="Password" 
           TextFieldType="TextFieldType.Password"
           PlaceHolder="********" @bind-Value="Input.Password"
           ValidationFor="@(() => Input.Password)" />

<div class="d-lg-flex justify-content-between align-items-center mb-4">
    <div class="form-check"></div>
    <a href="/Identity/Account/ForgotPassword">Forgot your password?</a>
</div>

<Button Text="Sign In" ButtonType="ButtonType.Submit" IsFullWidth="true" />
</EditForm>

AuthInput组件代码

@using Microsoft.AspNetCore.Components.Forms
@using System.Linq.Expressions
@inherits InputBase<string>

<div class="@ColSize">
    <div class="mb-3">
        <label for="@Id" class="form-label">@LabelText</label>
        <input id="@Id" name="@FieldName" @attributes="@AdditionalAttributes" class="form-control" type="@_type"
               required="@IsRequired" @bind="@Value" placeholder="@PlaceHolder" />
        <ValidationMessage For="ValidationFor" />
        <div class="invalid-feedback"></div>
    </div>
</div>

@code{
[Parameter] public string Id { get; set; }
[Parameter] public string LabelText { get; set; }
[Parameter] public string ColSize { get; set;  }
[Parameter] public string FieldName { get; set; }
[Parameter] public string PlaceHolder { get; set; }
[Parameter] public bool IsRequired { get; set; } = false;
[Parameter] public TextFieldType TextFieldType { get; set; } = TextFieldType.Text;
[Parameter] public Expression<Func<string>> ValidationFor { get; set; } = default!;

private string _type => TextFieldType == TextFieldType.Text ? "text" :
                        TextFieldType == TextFieldType.Number ? "number" :
                        TextFieldType == TextFieldType.Password ? "password" :
                        TextFieldType == TextFieldType.EmailAddress ? "email" :
                        "text";

protected override bool TryParseValueFromString(string value, out string result, out string validationErrorMessage)
{
    result = value;
    validationErrorMessage = null;
    return true;
}
}

后台代码声明

private FluentValidationValidator? _fluentValidationValidator;
private bool Validated => _fluentValidationValidator!.Validate(options => { 
                          options.IncludeAllRuleSets(); });
private TokenRequestModel Input { get; set; } = new();

原因分析

  1. 组件初始化顺序问题:_fluentValidationValidator通过@ref获取组件实例,而Blazor中@ref的赋值发生在组件首次渲染完成后。若Validated属性在组件初始化阶段(如OnInitialized、OnParametersSet)被访问,此时_fluentValidationValidator尚未赋值,使用!强制非空会触发空引用异常。
  2. 验证器未关联模型:FluentValidationValidator未指定对应TokenRequestModel的验证器类型或实例,导致内部验证逻辑依赖的对象为null。
  3. 双重验证器冲突:同时使用FluentValidationValidator和DataAnnotationsValidator可能引发内部状态冲突,导致验证器实例未正确初始化。

解决方案建议

1. 安全访问验证器实例

避免在组件初始化阶段访问Validated,或添加null安全检查:

  • 修改SubmitAsync方法,先检查验证器是否初始化:
private async Task SubmitAsync()
{
    if (_fluentValidationValidator == null)
    {
        // 处理验证器未就绪的情况,如提示用户重试
        return;
    }

    bool isValid = _fluentValidationValidator.Validate(options => options.IncludeAllRuleSets());
    if (!isValid) return;

    // 执行登录逻辑
}
  • 或修改Validated属性的实现:
private bool Validated => _fluentValidationValidator?.Validate(options => options.IncludeAllRuleSets()) ?? false;

2. 明确指定验证器类型

为FluentValidationValidator关联TokenRequestModel的验证器:

  • 若存在TokenRequestModelValidator类,直接指定类型:
<FluentValidationValidator @ref="@_fluentValidationValidator" 
                           ValidatorType="typeof(TokenRequestModelValidator)" />
  • 或通过DI注入验证器实例:
<FluentValidationValidator @ref="@_fluentValidationValidator" 
                           Validator="@tokenRequestValidator" />

后台注入:

[Inject] private IValidator<TokenRequestModel> tokenRequestValidator { get; set; } = default!;

3. 移除冲突验证器

若无需同时使用两种验证器,移除DataAnnotationsValidator以避免状态冲突:

<EditForm class="needs-validation" Model="@Input" OnValidSubmit="@SubmitAsync" FormName="login" novalidate>
<FluentValidationValidator @ref="@_fluentValidationValidator" />
<!-- 移除DataAnnotationsValidator -->

<!-- 其余代码保持不变 -->
</EditForm>

4. 检查服务注册

确保在Program.cs中正确注册Blazored.FluentValidation及自定义验证器:

builder.Services.AddBlazoredFluentValidation();
// 注册TokenRequestModel的验证器
builder.Services.AddScoped<IValidator<TokenRequestModel>, TokenRequestModelValidator>();

内容的提问来源于stack exchange,提问作者kyenry

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 15:35:05