在实现登录功能时,我在Blazor服务器应用程序中遇到了Blazore.FluentValidation的问题.以下是我的登录组件代码:

<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" />

我的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();

空引用异常: 根据文档,验证方法不应导致空引用异常.尽管在options.IncludeAllRuleSets()中包含了所有规则集,但我仍然面临这个错误.任何基于Blazore.FluentValidation文档的对原因的见解或解决方案的建议都将不胜感激.

The Null Exception

我已经遵循了Blazored.FluentValidation源代码控制的文档,但这些问题仍然存在.解决这些Blazored.FluentValidation问题的任何帮助、建议或代码示例.

推荐答案

您有两个问题:

为什么我得到一个空例外?

第一次渲染组件之前,_fluentValidationValidator为空:在第一次渲染之前,子组件[如FluentValidationValidator]不存在.

private FluentValidationValidator? _fluentValidationValidator;

因此,如果在第一次呈现之前try 使用Validated,则会出现异常,因为没有_fluentValidationValidator对象可以调用Validate._fluentValidationValidator!告诉编译器忽略空值验证判断,因为您更清楚代码_fluentValidationValidator中的这一点不能为空值.显然,情况并非如此.

private bool Validated => _fluentValidationValidator!.Validate(options => { 
                          options.IncludeAllRuleSets(); });

您可以像这样使用null-conditional operator,如果_fluentValidationValidator为空,则返回false.

private bool Validated => _fluentValidationValidator?.Validate(options => { 
                          options.IncludeAllRuleSets(); }) ?? false;

或者重构你的逻辑,在你知道_fluentValidationValidator不是null之前不要try 使用它.

在文档中,您可以看到这一点.此时您正在提交表单,因此必须存在_fluentValidationValidator个.

    private void SubmitFormAsync()
    {
        if (await _fluentValidationValidator!.ValidateAsync())
        {
            Console.WriteLine("Form Submitted Successfully!");
        }
    }

就我个人而言,除非迫不得已,否则我不喜欢使用空 suppress 操作符.我更喜欢带花括号的零条件运算符.

为什么我的AuthInput绑定不起作用?

你不能像现在这样用Bind美元.在组件中,您需要分别分配getter和setter.当您从InputBase继承时,您需要将这些连接到CurrentValueAsString中以插入到内置的InputBase逻辑中.

以下是组件的重构版本.我添加了一些注释,质疑您为什么有某些参数,因为我猜您放入这些参数是因为它们存在于 bootstrap 示例代码中.如果你有正当的理由,那就忽略我的 comments .我还重构了一些地方的可空性.

@using Microsoft.AspNetCore.Components.Forms
@using System.Linq.Expressions
@using System.Diagnostics.CodeAnalysis

@inherits InputBase<string>

<div class="@ColSize">
    <div class="mb-3">
        @if(this.LabelText is not null)
        {
            <label class="form-label">@LabelText</label>
        }
        <input @attributes="@AdditionalAttributes" class="form-control" type="@_type"
               required="@IsRequired" value="@this.CurrentValueAsString" @onchange="this.SetValue" placeholder="@PlaceHolder" />
        <ValidationMessage For="this.ValueExpression" />
        <div class="invalid-feedback"></div>
    </div>
</div>

@code {
    // Do you need this?
    //[Parameter] public string Id { get; set; }
    [Parameter] public string? LabelText { get; set; }
    [Parameter] public string ColSize { get; set; } = "col-12";
    // Do you need this?
    //[Parameter] public string FieldName { get; set; }
    [Parameter] public string PlaceHolder { get; set; } = "Enter a value";
    [Parameter] public bool IsRequired { get; set; } = false;
    [Parameter] public TextFieldType TextFieldType { get; set; } = TextFieldType.Text;

    // Why include number - InputBase<int> if it's a integer
    private string _type => TextFieldType == TextFieldType.Text ? "text" :
                            TextFieldType == TextFieldType.Number ? "number" :
                            TextFieldType == TextFieldType.Password ? "password" :
                            TextFieldType == TextFieldType.EmailAddress ? "email" :
                            "text";

    private void SetValue(ChangeEventArgs e)
    {
        this.CurrentValueAsString = e.Value?.ToString() ?? null;
    }

    protected override bool TryParseValueFromString(string? value, out string? result, [NotNullWhen(false)] out string? validationErrorMessage)
    {
        result = value;
        validationErrorMessage = null;
        return true;
    }
}

然后,本页演示了该控件的实际操作:

@page "/"

<PageTitle>Home</PageTitle>

<h1>Hello, world!</h1>

Welcome to your new app.
<EditForm Model="_model" >
    <AuthInput @bind-Value="_model.UserName" LabelText="User Name" PlaceHolder="Enter your user name" />

</EditForm>

<div class="bg-dark text-white m-2 p-2">
    <pre>User Name: @_model.UserName</pre>
</div>

@code {
    private Model _model = new();

    public class Model {
        public string? UserName { get; set; }

    }
}

Csharp相关问答推荐

Microsoft. SQLServer. Types(106.1000.6)在try 从用户定义的类型检索值时引发异常

LINQ无法翻译SQLFunctions方法

如何使用CsvReader获取给定列索引的列标题?

. NET在上一个操作完成之前,在此上下文实例上启动了第二个操作

在命名管道上使用GRPC ASP.NET核心时如何配置命名管道权限

从依赖项容器在.NET 8中的Program.cs文件中添加IOC

为什么无法将对象转换为泛型类型

每个http请求需要60秒,为什么?

将内置的OrderedEumable&Quot;类设置为内部类有什么好处?

委托RequestDelegate不带2个参数-ASP.NET Core 8最小API

try 链接被委派者(多播委托)时,无法将获取运算符应用于类型为';方法组&39;和方法组';的操作数

泛型参数在.NET 8 AOT中没有匹配的批注

CRL已过期,但ChainStatus告诉我RevocationStatus未知

Azure Functions v4中的Serilog控制台主题

两个DateTimeOffset之间的差异返回意外的负值

如何正确处置所有动态控件?

如何在Polly重试策略成功之前将HttpClient请求排队?

用MongoDB c#驱动程序删除和返回嵌套数组中的文档

使用本地公共PEM文件加密字符串,使用Azure KayVault中的私钥解密

如何处理ASP.NET Core中包含两个构造函数的控制器?