【问题标题】:How to conditionally validate entire model in ASP.NET Core Web API?如何有条件地验证 ASP.NET Core Web API 中的整个模型?
【发布时间】:2023-03-23 03:16:02
【问题描述】:

我在我的 Web 应用程序中使用 net core 3.1。我陷入了想有条件地验证模型的情况。以下是我的模型:

学生模型:

public class StudentModel 
{
  public int StudenId {get; set;}
  public string StudenName {get; set;}
  public bool HasSiblings {get; set;}
  public List<SiblingModel> SiblingDetails {get; set;}
}

兄弟模型

public class SiblinModel
{
  public int SiblingId {get; set;}
  [Required]
  public string SiblingName {get; set;}
}

现在,我只想在 StudentModel 中的 HasSibling 设置为 true 时验证 SiblingModel。

注意:我不想使用 IValidatableObject 然后验证 SiblingModel 的每个属性。我仅以上述模型为例。在实际模型中,我验证了大约 10-12 个字段。因此,为每个属性编写验证检查将是一项乏味的任务。

有没有一种方法可以有条件地验证整个模型,即如果 HasSibling 设置为 true,则仅验证同级模型。

另外,我在我的项目中使用操作过滤器来自动检查每个请求中的验证。

public class ValidationFilterAttribute : ActionFilterAttribute
{

    public override void OnActionExecuting(ActionExecutingContext context)
    {

        if (!context.ModelState.IsValid)
        {

            ApiResponseModel<IEnumerable<ValidationErrorModel>> apiResponseModel = new ApiResponseModel<IEnumerable<ValidationErrorModel>>();

            apiResponseModel.ResponseCode = (int)HttpStatusCode.BadRequest;
            apiResponseModel.ResponseMessage = string.Join(" ",
                context.ModelState.Values.Where(E => E.Errors.Count > 0)
                .SelectMany(E => E.Errors)
                .Select(E => E.ErrorMessage)
                .ToArray());
            apiResponseModel.ResponseData = null;

            context.Result = new OkObjectResult(apiResponseModel);
        }
    }
}

那么有什么办法,或者我必须使用 IValidatableObject 手动编写验证检查。

【问题讨论】:

    标签: c# asp.net-web-api asp.net-core-webapi


    【解决方案1】:

    嗯,你的问题是模棱两可的:

    有没有一种方法可以验证整个模型 有条件的,即如果 HasSibling 设置为 true,则仅验证 兄弟模型。

    如果你想基于一个属性来验证整个模型,使用ActionFilter 是一个不错的选择。如果您想根据以下解决方案的另一个属性有条件地验证一个属性。

    这是RequiredIf属性的示例:

    public sealed class RequiredIfAttribute : ValidationAttribute
    {
        private readonly RequiredAttribute _innerRequiredAttribute = new RequiredAttribute();
        private readonly string _dependentPropertyName;
        private readonly object[] _targetValues;
    
        public RequiredIfAttribute(string dependentPropertyName, params object[] targetValues)
        {
            _dependentPropertyName = dependentPropertyName;
            _targetValues = targetValues;
        }
    
        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            var containerType = validationContext.ObjectInstance.GetType();
            var field = containerType.GetProperty(_dependentPropertyName);
    
            if (field == null)
                return ValidationResult.Success;
    
            // get the value of the dependent property
            var dependentValue = field.GetValue(validationContext.ObjectInstance, null);
    
            foreach (var obj in _targetValues)
            {
                // compare the value against the target value
                if (dependentValue.GetHashCode().Equals(obj.GetHashCode()))
                {
                    // match => means we should try validating this field
                    if (!_innerRequiredAttribute.IsValid(value))
                        // validation failed - return an error
                        return new ValidationResult(ErrorMessage, new[] { validationContext.MemberName });
                }
            }
            return ValidationResult.Success;
        }
    }
    

    在你的模型中:

    public class StudentModel 
    {
      public int StudenId {get; set;}
    
      public string StudenName {get; set;}
    
      public bool HasSiblings {get; set;}
    
      [RequiredIf(nameof(HasSiblings), true)]
      public List<SiblingModel> SiblingDetails {get; set;}
    }
    

    【讨论】:

    • 自定义属性将不起作用,因为对于模型验证,我正在使用操作过滤器。因此,在调用RequiredIf 属性之前,尽管HasSiblings 已设置为false,但操作过滤器将返回验证错误
    • 我无法删除操作过滤器,因为对于其他模型,验证非常简单,但仅对于某些模型,我必须使用条件验证检查。因此,当我使用操作过滤器时,您的解决方案将不起作用。
    • 无论您在操作过滤器中验证整个模型的位置还是通过调用ModelState.IsValid 条件验证都有效。
    猜你喜欢
    • 1970-01-01
    • 2018-08-24
    • 1970-01-01
    • 2019-03-26
    • 2020-12-09
    • 1970-01-01
    • 1970-01-01
    • 2019-03-16
    相关资源
    最近更新 更多