繁体   English   中英

Blazor 服务器端的日期验证器

[英]Date validator in Blazor Server Side

我的 blazor 服务器端组件有一个简单的输入 model。 我想对两个 DateTime 属性使用内置验证。

[DataType(DataType.Date)]
public DateTime? FromDate { get; set; }
[DataType(DataType.Date)]
public DateTime? ToDate { get; set; }

我怎么能只接受 ToDate > FromDate?

使用自定义ValidationAttribute的解决方案:

DateMustBeAfterAttribute.cs:

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class DateMustBeAfterAttribute : ValidationAttribute
{
    public DateMustBeAfterAttribute(string targetPropertyName)
        => TargetPropertyName = targetPropertyName;

    public string TargetPropertyName { get; }

    public string GetErrorMessage(string propertyName) =>
        $"'{propertyName}' must be after '{TargetPropertyName}'.";

    protected override ValidationResult? IsValid(
        object? value, ValidationContext validationContext)
    {
        var targetValue = validationContext.ObjectInstance
            .GetType()
            .GetProperty(TargetPropertyName)
            ?.GetValue(validationContext.ObjectInstance, null);
        
        if ((DateTime?)value < (DateTime?)targetValue)
        {
            var propertyName = validationContext.MemberName ?? string.Empty;
            return new ValidationResult(GetErrorMessage(propertyName), new[] { propertyName });
        }

        return ValidationResult.Success;
    }
}

DateMustBeBeforeAttribute.cs:

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class DateMustBeBeforeAttribute : ValidationAttribute
{
    public DateMustBeBeforeAttribute(string targetPropertyName)
        => TargetPropertyName = targetPropertyName;

    public string TargetPropertyName { get; }

    public string GetErrorMessage(string propertyName) =>
        $"'{propertyName}' must be before '{TargetPropertyName}'.";

    protected override ValidationResult? IsValid(
        object? value, ValidationContext validationContext)
    {
        var targetValue = validationContext.ObjectInstance
            .GetType()
            .GetProperty(TargetPropertyName)
            ?.GetValue(validationContext.ObjectInstance, null);

        if ((DateTime?)value > (DateTime?)targetValue)
        {
            var propertyName = validationContext.MemberName ?? string.Empty;
            return new ValidationResult(GetErrorMessage(propertyName), new[] { propertyName });
        }

        return ValidationResult.Success;
    }
}

用法:

public class DateTimeModel
{
    [Required]
    [DateMustBeBefore(nameof(ToDate))]
    [DataType(DataType.Date)]
    public DateTime? FromDate { get; set; }

    [Required]
    [DateMustBeAfter(nameof(FromDate))]
    [DataType(DataType.Date)]   
    public DateTime? ToDate { get; set; }
}

这些字段是链接的,因此我们需要在其中任何一个更改以重新验证另一个时通知EditContext

示例EditForm

<EditForm EditContext="editContext" OnInvalidSubmit="@HandleValidSubmit">
    <DataAnnotationsValidator />
    <ValidationSummary />

    <p>
        <label>
            From Date:
            <InputDate TValue="DateTime?"
                       Value="dateTimeModel.FromDate"
                       ValueChanged="HandleFromDateChanged"
                       ValueExpression="() => dateTimeModel.FromDate" />
        </label>
        <ValidationMessage For="@(() => dateTimeModel.FromDate)" />
    </p>

    <p>
        <label>
            To Date:
            <InputDate TValue="DateTime?"
                       Value="dateTimeModel.ToDate"
                       ValueChanged="HandleToDateChanged"
                       ValueExpression="() => dateTimeModel.ToDate" />
        </label>
        <ValidationMessage For="@(() => dateTimeModel.ToDate)" />
    </p>

    <button type="submit">Submit</button>
</EditForm>

@code {
    private EditContext? editContext;
    private DateTimeModel dateTimeModel = new();

    protected override void OnInitialized()
    {
        editContext = new EditContext(dateTimeModel);
    }

    private void HandleFromDateChanged(DateTime? fromDate)
    {
        dateTimeModel.FromDate = fromDate;

        if (editContext != null && dateTimeModel.ToDate != null)
        {
            FieldIdentifier toDateField = editContext.Field(nameof(DateTimeModel.ToDate));
            editContext.NotifyFieldChanged(toDateField);
        }
    }

    private void HandleToDateChanged(DateTime? toDate)
    {
        dateTimeModel.ToDate = toDate;

        if (editContext != null && dateTimeModel.FromDate != null)
        {
            FieldIdentifier fromDateField = editContext.Field(nameof(DateTimeModel.FromDate));
            editContext.NotifyFieldChanged(fromDateField);
        }
    }

    private void HandleValidSubmit()
    {
    }
}

Blazor 小提琴示例

GitHub 带演示的存储库

使用IValidatableObject解决方案:

要进行更复杂的验证检查,您的 model 可以继承IValidatableObject接口并实现Validate方法:

public class ExampleModel : IValidatableObject
{
    [DataType(DataType.Date)]
    public DateTime? FromDate { get; set; }

    [DataType(DataType.Date)]
    public DateTime? ToDate { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (ToDate < FromDate)
        {
            yield return new ValidationResult("ToDate must be after FromDate", new[] { nameof(ToDate) });
        }
    }
}

Blazor 小提琴示例

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM