ASP.NET Core 中 IModelValidatorProvider 和 IModelValidator 实现的问题模型验证错误未显示

问题描述

任务考虑两种形式:

因此,第一个表单允许根据数据注释输入具有相应字段验证的数据。同时第二个表单设计为以只读模式显示相同的数据以供最终确认。

还有一个想法是对第一个表单使用模型验证。 假设数据注释用于简单的验证,如字段值长度和字段值内容。同时模型验证将用于更复杂的数据验证。例如,某些操作类型只需要一些额外的数据。否则不需要额外的数据。这个额外的数据可以有自己的验证要求等等。因此验证逻辑可能非常复杂,并且需要有关整个模型的信息。这就是为什么有使用模型验证的想法。

在之前的 question 中提出了如何启用模型验证的建议。

但我注意到了一些意想不到的行为。通过按下第一个表单上的提交按钮来触发验证。运行两种类型的验证(表单字段数据注释和表单验证)。 没事。但验证消息仅基于字段数据注释显示。未显示基于模型验证的验证错误。它们仅在下一个表格中可用。第二种形式(确认)ModelState 包含这些错误。但是我们说已经太晚了。这个想法是在第一个表单上显示这些错误(来自模型验证)。更重要的是,我希望在模型验证错误的情况下不应该发生 post 操作(确认页面调用)。

让我分享没有所有字段的源代码。因为视图和相应的视图模型包含大约 20 个字段。

请在下面找到视图模型的部分

public class DealRegistrationviewmodel : Baseviewmodel 
{
        [display(Name = "Код (для получения котировок с биржи)")]
        [StringLength(10,MinimumLength = 0)]
        [RegularExpression(@"^[a-zA-Z]+$",ErrorMessage = "Неверное значение")]
        public string Code { get; set; }

        [required]        
        public int SelectedSecuritiesTypeId { get; set; }

        [display(Name = "Вид")]
        public List<SecuritiesType> SecuritiesTypes { get; set; }
}

请在下方找到相应的部分

<div class="row">
    <div class="col-md-4">
        <form asp-action="Confirmation">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="SecuritiesTypes" class="control-label"></label>
                <br>
                <select asp-for="SelectedSecuritiesTypeId" asp-items="@(new SelectList(Model.SecuritiesTypes,"Id","Description"))"></select>
                <br>
                <span asp-validation-for="SelectedSecuritiesTypeId" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Code" class="control-label"></label>
                <input asp-for="Code" class="form-control"/>
                <span asp-validation-for="Code" class="text-danger"></span>
            </div>

请在下面找到 IModelValidator.Validate 方法的实现

public IEnumerable<ModelValidationResult> Validate(ModelValidationContext context)
        {
            var model = context.Container as WAVM.DealRegistrationviewmodel;

            if (model == null)
            {
                throw new ArgumentNullException("Container is null");
            }

            if (context.ModelMetadata.Name.Equals(nameof(model.Code)) == false
                && context.ModelMetadata.Name.Equals(nameof(model.SelectedSecuritiesTypeId)) == false)
            {
                return Enumerable.Empty<ModelValidationResult>();
            }

            BLI.SecuritiesType type = _securitiesService.GetItemAsync(model.SelectedSecuritiesTypeId).GetAwaiter().GetResult();

            if (type == null)            
            {
                return new List<ModelValidationResult>
                    {
                        new ModelValidationResult("",$"Не найден тип ценной бумаги по коду ({model.SelectedSecuritiesTypeId})")
                    };
            }

            if (type.IsRateRequestAllowed == true && string.IsNullOrEmpty(model.Code) == true)
            {
                if (context.ModelMetadata.Name == nameof(model.Code))
                {
                    return new List<ModelValidationResult>
                    {
                        new ModelValidationResult("","Пустое значение поля Код не допустимо")
                    };
                }

                if (context.ModelMetadata.Name == nameof(model.SelectedSecuritiesTypeId))
                {
                    return new List<ModelValidationResult>
                    {
                        new ModelValidationResult("","Выбранный тип ценной бумаги требует значения для поля Код")
                    };
                }
            }

            if (type.IsRateRequestAllowed == false && string.IsNullOrEmpty(model.Code) == false)
            {
                if (context.ModelMetadata.Name == nameof(model.Code))
                {
                    return new List<ModelValidationResult>
                    {
                        new ModelValidationResult("","Значение поля Код должно быть пустым")
                    };
                }

                if (context.ModelMetadata.Name == nameof(model.SelectedSecuritiesTypeId))
                {
                    return new List<ModelValidationResult>
                    {
                        new ModelValidationResult("","Выбранный тип ценной бумаги не допускает значения для поля Код")
                    };
                }
            }

            return Enumerable.Empty<ModelValidationResult>();
        }

执行正确地在每个“返回新列表”的断点处停止

请在下面找到 IModelValidatorProvider.CreateValidators 方法的实现

public void CreateValidators(ModelValidatorProviderContext context)
{
    if (context.Results.Any(v => v.Validator.GetType() == typeof(DealRegistrationviewmodelValidator)) == true)
    {
        return;
    }

    if (context.ModelMetadata.ContainerType == typeof(DealRegistrationviewmodel) 
            && ( context.ModelMetadata.Name == nameof(DealRegistrationviewmodel.Code) 
                || context.ModelMetadata.Name == nameof(DealRegistrationviewmodel.SelectedSecuritiesTypeId)) )
    {
        context.Results.Add(new ValidatorItem
        {
            Validator = new DealRegistrationviewmodelValidator(_securitiesService),IsReusable = true
        });
    }
}

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)