例如,考虑一下逻辑“用户只能编辑或删除用户已创作的评论”。
我的控制器动作将重复检查当前登录用户是否可以影响评论的逻辑。例子
[Authorize]
public ActionResult DeleteComment(int comment_id)
{
var comment = CommentsRepository.getCommentById(comment_id);
if(comment == null)
// Cannot find comment, return bad input
return new HttpStatusCodeResult(400);
if(comment.author != User.Identity.Name)
// User not allowed to delete this comment, return Forbidden
return new HttpStatusCodeResult(403);
// Error checking passed, continue with delete action
return new HttpStatusCodeResult(200);
}
当然,我可以将该逻辑捆绑在一个方法中,这样我就不会复制/粘贴该片段;但是,将该代码从控制器中取出并将其放入 ValidationAttribute 可以使我的 Action 更小,更容易编写测试。例子
public class MustBeCommentAuthorAttribute : ValidationAttribute
{
// Import attribute for Dependency Injection
[Import]
ICommentRepository CommentRepository { get; set; }
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
int comment_id = (int)value;
var comment = CommentsRepository.getCommentById(comment_id);
if(comment == null)
return new ValidationResult("No comment with that ID");
if(comment.author != HttpContext.Current.User.Identity.Name)
return new ValidationResult("Cannot edit this comment");
// No errors
return ValidationResult.Success;
}
}
public class DeleteCommentModel
{
[MustBeCommentAuthor]
public int comment_id { get; set; }
}
模型验证是这项工作的正确工具吗?我喜欢将这种担忧从控制器动作中解脱出来;但在这种情况下,它可能会使事情进一步复杂化。当您认为此操作是 RESTful API 的一部分并且需要根据 ModelState 中的验证错误返回不同的 HTTP 状态代码时,尤其如此。
在这种情况下是否有“最佳实践”?