【问题标题】:Custom validation - Required only when method is put自定义验证 - 仅在放置方法时需要
【发布时间】:2019-07-18 18:23:19
【问题描述】:

我有两个 API 端点,post 和 put:

    [HttpPost]
    [Route("projects")]
    public IHttpActionResult Create([FromBody] ProjectDTO projectDto)
    {
        if (ModelState.IsValid)
        {
                var project = MappingConfig.Map<ProjectDTO, Project>(projectDto);
                _projectService.Create(project);

                return Ok("Project successfully created.");
        }
        else 
        { 
            return BadRequest(ModelState); 
        }
    }

    [HttpPut]
    [Route("projects")]
    public IHttpActionResult Edit([FromBody] ProjectDTO projectDto)
    {
        if (ModelState.IsValid)
        {
            var project = _projectService.GetById(projectDto.ProjectId);
            if (project == null)
                return NotFound();

            project = Mapper.Map(projectDto, project);
            _projectService.Update(project);

            return Ok("Project successfully edited.");
        }
        else 
        { 
            return BadRequest(ModelState); 
        }
    }

DTO 看起来像这样:

    public class ProjectDTO
    {
           public int ProjectId { get; set; }
           [Required(ErrorMessage = "Name field is required.")]
           public string Name { get; set; }
           [Required(ErrorMessage = "IsInternal field is required.")]
           public bool IsInternal { get; set; }
    }

我正在尝试验证字段 ProjectId。编辑实体时,只有在 HttpPut 方法中才需要 ProjectId 字段。

是否可以进行自定义验证RequiredIfPut 或类似的东西,该字段仅在编辑时需要,但在创建时不需要?

【问题讨论】:

    标签: c# .net rest api asp.net-web-api2


    【解决方案1】:

    您可以使用自定义验证属性执行以下操作:

     public class RequiredWhenPutAttribute : ValidationAttribute
        {
            protected override ValidationResult IsValid(object value, ValidationContext validationContext)
            {
                if (System.Web.HttpContext.Current.Request.HttpMethod == "PUT")
                {
                    var obj = (ProjectDTO)validationContext.ObjectInstance;
                    if (obj.ProjectId == null)
                    {
                        return new ValidationResult("Project Id is Required");
                    }
                }
                else
                {
                    return ValidationResult.Success;
                }
            }
        }
    
        public class ProjectDTO
        {
            [RequiredWhenPut]
            public int? ProjectId { get; set; }
        }
    

    更新:

    针对您的评论,为了使解决方案更通用,您可以添加一个ParentDto类,从该类继承其他类并且共享属性需要在ParentDto类中,如下所示:

     public class RequiredWhenPutAttribute : ValidationAttribute
        {
            protected override ValidationResult IsValid(object value, ValidationContext validationContext)
            {
                if (HttpContext.Current.Request.HttpMethod == "PUT")
                {
                    var obj = (ParentDto)validationContext.ObjectInstance;
                    if (obj.Id == null)
                    {
                        return new ValidationResult(ErrorMessage);
                    }
                }
                else
                {
                    return ValidationResult.Success;
                }
            }
        }
        public class ParentDto
        {
            [RequiredWhenPut(ErrorMessage = "Id is required")]
            public int? Id { get; set; }
        }
        public class UserDTO : ParentDto
        {
            // properties
        }
        public class ProjectTypeDTO : ParentDto
        {
            // properties
        }
        public class ProjectDTO : ParentDto
        {
             // properties
        }
    

    【讨论】:

    • 酷,这行得通。有什么办法可以让这个更通用吗?因为我得到了更多的实体,不仅是 ProjectDTO,我还有 UserDTO、ProjectTypeDTO 等。那么我怎样才能使它更通用并为所有这些实体使用相同的验证属性呢? @rad
    • 答案已更新。 ErrorMessage 也是动态的。
    【解决方案2】:

    这就是为什么我对这两种情况都使用不同的类的原因之一(例如ProjectUpdateRequestDto 和ProjectCreateRequestDto)。也许两者都可以从一个公共基类派生,但即使不是,也可以更容易区分这两种情况。

    安全性也可能是一个问题,因为如果您使用相同的类,则创建请求可能已经包含一个 id,并且如果您的创建方法只是将 DTO 映射到数据库实体,您可能会覆盖现有数据。这意味着您必须小心并考虑此类情况。如果您创建的 DTO 类没有该属性,则无法从映射器中设置它并且不能被滥用。

    【讨论】:

      猜你喜欢
      • 2018-07-11
      • 1970-01-01
      • 2019-12-01
      • 1970-01-01
      • 2018-11-21
      • 2018-05-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多