«пользователь может сделать X, если пользователь владеет объектом Y»: реализовать логику в проверке модели или логике контроллера? - PullRequest
3 голосов
/ 17 февраля 2012

Рассмотрим, например, логику «Пользователь может редактировать или удалять только комментарий, созданный пользователем».

Действия моего контроллера будут повторять логику проверки, может ли пользователь, вошедший в систему в данный момент.повлиять на комментарий.Пример

[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, вы уменьшаете размер моего действия и упрощаете написание тестов.Пример

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 и должно возвращать другой код состояния HTTP в зависимости от ошибок валидации в ModelState.

Существует ли в этом случае «наилучшая практика»?

1 Ответ

0 голосов
/ 18 февраля 2012

Лично я думаю, что это выглядит красиво, но вы увлекаетесь аннотациями.Я думаю, что это не относится к вашему уровню представления и должно обрабатываться вашим уровнем обслуживания.

У меня будет что-то вроде:

[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
    }
} 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...