Strongly typed models on your layout

One of the early issues I disliked when moving to .net’s MVC was the lack of strongly typed objects available in layout pages. A lot of times I’ll want to display failry static, session(ish) type information in a many places “around” the main content area.

Information like the current users name, email and even other not so generic information like permissions (we rolled our own permissions architecture) or current context (our website has many “portals”) all seemed like fair game. I also noticed many times we’ll need this information in the main content view or even on a partial/ajax request.

A couple solutions came to mind.

I initially created many partial actions which retrieved the specific information I needed for the particular area but soon found that to be too cumbersome. Even if all the information I needed was cached in nHibernate for the entire request, why must I go a round about way to get it each time.

Another solution was to stick what I needed in the context object, or even the ‘He-Who-Must-Not-Be-Named’ – señor ViewBag. Again though leading back to my original thesis – I wanted this to be typed safe – so I finally settled on this quick and simple solution.

First I created a simple view model, added any dependencies and populated it with the info I’d want available to my layouts and views.

public class BaseViewModel
{
   private readonly IContextRepository _contextRepository;

   public BaseViewModel(IContextRepository contextRepository)
   {
      _contextRepository = contextRepository;
      SelectedContext = _contextRepository.GetCurrent();
   }
   // assume for the sake of the example a ContextViewModel is just a simple dto with an Id and Name representing a context business object
   public ContextViewModel SelectedContext { get; private set;  }
}

Then in my base controller, during the OnActionExecuting I create the BaseViewModel using my resolver. It’s important to note that the BaseViewModel (and all of it’s properties) gets created between the unitOfWork transaction to ensure I’m not accessing the database at the view level. If there’s questions about why it’s important, I’ll make another blog post soon to respond.

public class BaseController : Controller
{
  protected BaseViewModel ModelBase { get; private set; }

  private readonly IMapService _mapService = Resolver.Get<IMapService>();
  private IUnitOfWork _unitOfWork;

  protected override void OnResultExecuting(ResultExecutingContext filterContext)
  {
    var contextItems = filterContext.HttpContext.Items;
    if (contextItems["ModelBase"] == null)
      contextItems["ModelBase"] = ModelBase;
    base.OnResultExecuting(filterContext);
  }

  protected override void OnActionExecuting(ActionExecutingContext filterContext)
  {
    _unitOfWork = Resolver.Get<IUnitOfWork>();
    _unitOfWork.BeginTransaction();
            
    ModelBase = new BaseViewModel(Resolver.Get<IContextRepository>());
            
    base.OnActionExecuting(filterContext);
  }
  //...
}

After creating it, I simply place it in the contextItems dictionary to be used by the views – simple as that. This allows type safe, transaction safe references to information in the layouts, and really all over the place.

_layout.cshtml

...
<div>Hey there you're in the @ModelBase.SelectedContext.Name section of our site!</div>
...

The naming is especially nice since intellisense will pick up the BaseViewModel when the developer types “Model” as he’ll see “ModelBase” in the drop down and hopefully remember to use it. It’s also made refactoring quite a bit easier as we now have one place to make modifications to retrieving that commonly used information.

(Now of course with great power…)
Make sure you only put in to this baseViewModel what you’ll be accessing quite often (nearly if not every request) otherwise obviously you won’t get as much out of it as you could. It’s also recommended, like always, if you are working with a view model of any kind, keep it to primitives or dtos of primitives mapped via nHibernate or AutoMapper.

Please don’t expose your entire user/company/kitchenSink object using this method as I’ll plead the 5th. =P

-D^t

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s