自定义验证 - 仅在放置方法时需要
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 的原因之一(例如 ProjectUpdateRequestDto
和 ProjectCreateRequestDto
)。也许两者都可以从一个共同的基础派生出来 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
}
我有两个 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 的原因之一(例如 ProjectUpdateRequestDto
和 ProjectCreateRequestDto
)。也许两者都可以从一个共同的基础派生出来 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
}