3

例如,考虑一下逻辑“用户只能编辑或删除用户已创作的评论”。

我的控制器动作将重复检查当前登录用户是否可以影响评论的逻辑。例子

[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 状态代码时,尤其如此。

在这种情况下是否有“最佳实践”?

4

1 回答 1

0

就个人而言,我认为它看起来不错,但是您对注释感到厌烦。我认为这不属于您的表示层,应该由您的服务层处理。

我会有以下内容:

[Authorize] 
public ActionResult DeleteComment(int comment_id) 
{ 
    try
    {
       var result = CommentsService.GetComment(comment_id, Auth.Username);

       // Show success to the user
    }
    catch(Exception e)
    {
       // Handle by displaying relevant message to the user
    }
} 
于 2012-02-17T23:50:09.567 回答