{STATIC} hippo

...on becoming a great developer...
MCTS: .NET Framework 3.5, ASP.NET Applications
posts - 29, comments - 6, trackbacks - 0

My Links

Twitter

Archives

Post Categories

Friday, January 08, 2010

ASP.NET MVC & State Pattern: Choose your view

Problem

I have a model that uses the State pattern.  Some States allow read/write access to the Model’s properties and some are read-only.  I wanted a good way to separate the logic for this from my Views; the View shouldn’t have to decide whether properties are displayed as TextBoxes or inside Divs.

First Thought

At first I was going to create a custom ViewEngine.  That ViewEngine would be responsible for choosing the right View – that is, if the View was called “Edit” but the model was in a readonly state, it would change the View to “ReadOnly”.  However, that just didn’t sound right – why was that responsibility falling on the ViewEngine?  Plus, it’s kind of inflexible – what if some editable Views are called “Edit” but some are called “Details”.

Solution

I ended up with a mixture of a custom ActionFilter and a base Controller class.  Before I show you the code, let me show you the usage:

   1: [AcceptVerbs(HttpVerbs.Get)]
   2: [StateItemEditView("ReadOnly")]
   3: public ActionResult Edit(int id)
   4: {
   5:     var module = _Repository.GetByID(id);
   6:     return View(module);
   7: }

Notice Line 2 – this specifies that:

  1. The current action has editable content
  2. The ReadOnly View name is called “ReadOnly”

The code for the controller, which I use as a base class for my controllers that act upon StateItems:

   1: public class StateItemController : Controller
   2: {
   3:     protected override ViewResult View(string viewName, string masterName, object model)
   4:     {
   5:         object readOnlyViewName;
   6:         if (ControllerContext.Controller.TempData
   7:             .TryGetValue(StateItemEditViewAttribute.key_ReadOnlyView, out readOnlyViewName))
   8:         {
   9:             var stateItem = model as IStateItem;
  10:             if (workflowItem != null && stateItem.CurrentState.IsReadOnly)
  11:                 viewName = readOnlyViewName as string;
  12:         }
  13:         return base.View(viewName, masterName, model);
  14:     }
  15: }

Before returning the View, which has a ViewName string, we want to make sure the ViewName is correct.  We check the Controller’s TempData for a predefined key.  If that key exists, the value will be the name of the View to display for ReadOnly states.  We then check if the Model exists and is a StateItem, and if it’s ReadOnly we change the ViewName before returning the View.

The StateItemEditViewAttribute is just responsible for setting the TempData key:

   1: public class StateItemEditViewAttribute : ActionFilterAttribute
   2: {
   3:     public StateItemEditViewAttribute(string readOnlyView)
   4:     {
   5:         _ReadOnlyView = readOnlyView;
   6:     }
   7:     private string _ReadOnlyView;
   8:     public const string key_ReadOnlyView = "ReadOnlyView";
   9:     public override void OnActionExecuting(ActionExecutingContext filterContext)
  10:     {
  11:         filterContext.Controller.TempData.Add(key_ReadOnlyView, _ReadOnlyView);
  12:     }
  13: }

I’m using this for a binary dicision – Edit/ReadOnly – but this could be used for a lot of other purposes too.

posted @ Friday, January 08, 2010 2:10 PM | Feedback (0) | Filed Under [ ASP.NET MVC ]

Powered by: