自定义验证 - 仅在放置方法时需要

Custom validation - Required only when method is put

我有两个 API 端点,post 并输入:

    [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。 ProjectId 字段应该只在我编辑我的实体时在 HttpPut 方法中需要。

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

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

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

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

 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 class 继承其他 classes 并共享 属性 需要在 ParentDto class 中,如下所示:

 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
    }