03 June 2011

MVC Issue Tracker Part 4

This is the penultimate entry in this series.  I’ve completed the code to the level I intend (for the moment) and I’ve verified things work as I expect (for the moment).

So, let’s look at what we had left to do:

  • Wire up WorkNote/Create so that it would redirect back to the underlying issue instead of to the index of WorkNote.
  • Provide Security.

The first was easy, instead of using “RedirectToAction(“Index”) I changed the code for "Create” to this:

   1: [HttpPost]
   2:         public ActionResult Create(WorkNote worknote)
   3:         {
   4:             if (ModelState.IsValid)
   5:             {
   6:                 var issueId = db.Issues.Where(i => i.IssueId == worknote.IssueId).SingleOrDefault();
   7:                 worknote.EnteredBy = this.HttpContext.User.Identity.Name;
   8:                 worknote.LoggedDate = DateTime.Now;
   9:                 db.WorkNotes.Add(worknote);
  10:                 db.SaveChanges();
  11:                 return RedirectToAction("Details", "Issue", new { id = issueId.IssueId });   
  12:             }
  13:  
  14:             ViewBag.IssueId = new SelectList(db.Issues, "IssueId", "Title", worknote.IssueId);
  15:             return View(worknote);
  16:         }

Ignore the “IssueId” and “EnteredBy” stuff for now.  The important part is at the end: “return RedirectToAction(“Details”, “Issue”, new {id = issueId.IssueId})';  This tells the controller that, on a successful insert, it should redirect to the “Details” view of the Issue with a specified issue id.

See?  Easy.

The next part required some extensive refactoring.  I was going to implement my own security model, but that’s really fairly silly.  MVC3 provides us with a perfectly acceptable method of Role based security, so we’ll just hook into that.

First, I removed the User class and Role enum, and all the references to same.  Then, using the configuration button, I used the built-in web-based configuration to set up roles, and add a couple of users.

From there, it was all markup.  Some samples follow:

   1: [Authorize(Roles="Administrators,Manager,Developer,User")]
   2:     public class WorkNoteController : Controller

This piece just says that only someone logged in as an Admin, Manager, Dev, or User can get to the WorkNoteController.  I have similar authorization on Issue.

More significantly, on Issue, I marked up some of the specific methods for the IssueController:

   1: [Authorize(Roles = "Administrators,Manager,Developer")]
   2:         [HttpPost]
   3:         public ActionResult Edit(Issue issue)
   4:         {
   5:             if (ModelState.IsValid)
   6:             {
   7:                 if (issue.ClosedDate != null) issue.ClosedBy = this.HttpContext.User.Identity.Name;
   8:                 db.Entry(issue).State = EntityState.Modified;
   9:                 db.SaveChanges();
  10:                 return RedirectToAction("Index");
  11:             }
  12:             return View(issue);
  13:         }
   1: [Authorize(Roles = "Administrators,Manager")]
   2: [HttpPost, ActionName("Delete")]
   3: public ActionResult DeleteConfirmed(int id)
   4: {            
   5:     Issue issue = db.Issues.Find(id);
   6:     db.Issues.Remove(issue);
   7:     db.SaveChanges();
   8:     return RedirectToAction("Index");
   9: }

These are specific authorizations required to access specific views: Edit and Delete, respectively.

So, now, an Administrator would have to create a new user (as one would expect in a business scenario) and provide that user with the correct credentials.  That user would then only be able to access the parts available to the assigned Role.  Basically, a basic user can add issues and can look at issue details/status.  A Developer can do that, but can also edit issues (specifically to close them, when necessary) and add work notes.  Managers and Administrators have the additional authority to delete issues.

Additionally, since I’m able to use the provided Role based security, I’m also able to avoid the necessity of a “User” object, and just grab the UserName from the Session.  This allows tagging that is just as accurate as building role-based security from scratch, and that is more intuitive, since I can just grab the username instead of the user’s Id, or going through some hoops to take that Id and turn it into their name.

The final code push is up on CodePlex now, and I’ll zip it all up and add it to the downloads folder soon as well.

Next Up (In a couple of days): A look back, and my impressions from working with MVC3.

No comments:

Post a Comment