"Benutzer darf X tun, wenn Benutzer Objekt Y besitzt": Logik in Modellvalidierung oder Controller-Logik implementieren?

StackOverflow https://stackoverflow.com/questions/9333916

  •  27-10-2019
  •  | 
  •  

Frage

Betrachten Sie beispielsweise die Logik "Ein Benutzer darf nur einen Kommentar bearbeiten oder löschen, den der Benutzer verfasst hat".

Meine Controller-Aktionen wiederholen die Logik der Überprüfung, ob der aktuell angemeldete Benutzer den Kommentar beeinflussen kann.Beispiel

[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);
}

Natürlich kann ich diese Logik in einer Methode bündeln, damit ich dieses Snippet nicht kopiere / einfüge.Wenn Sie diesen Code jedoch aus dem Controller entfernen und in ein ValidationAttribute einfügen, bleibt meine Aktion kleiner und es ist einfacher, Tests für sie zu schreiben.Beispiel

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; }
}

Ist die Modellvalidierung das richtige Werkzeug für diesen Job?Ich nehme dieses Anliegen gerne aus der Controller-Aktion heraus.In diesem Fall kann dies die Dinge jedoch noch komplizierter machen.Dies gilt insbesondere dann, wenn Sie berücksichtigen, dass diese Aktion Teil einer RESTful-API ist und abhängig von den Validierungsfehlern im ModelState einen anderen HTTP-Statuscode zurückgeben muss.

Gibt es in diesem Fall "Best Practice"?

War es hilfreich?

Lösung

Persönlich finde ich, dass es gut aussieht, aber Sie werden von Anmerkungen mitgerissen.Ich denke, dass dies nicht in Ihre Präsentationsschicht gehört und von Ihrer Serviceschicht behandelt werden sollte.

Ich hätte etwas in der Art von:

[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
    }
} 

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top