MonoRail - Runtime Views and Layouts with Filters

I've been on a bit of a MonoRail kick lately and thought I might share some gems.  In his recent post Hammett talks about, among other things, using a filter to change layouts at runtime.  He didn't elaborate so I thought I would share the way I've implemented his idea.  In our hosted environment we generally prefer each customer to have a separate host header.  For various reasons this isn't possible for some customers.  Instead, we identify them based on an internal id.  We key everything about the application off of this id.  We use this id to display a customized user interface and run custom logic on a per customer basis.  The way I am currently implementing the customized user interface is, as Hammett stated, with Filter. 

We grab the CustomerId from the query string and use that to determine if that particular customer has a custom view using a simple folder structure: Views -> CustomerId -> Controller -> View.brail.  If no custom view is found, we instead use a 'base' view that is stored in an identical structure Views -> Base -> Controller -> View.brail.  Pretty straight forward.  We do the same thing for layouts.  Decorate your base controller with an AfterAction attribute and you are all set.

namespace My.Product.Mvc
{
  using System.IO;
  using Castle.MonoRail.Framework;

  public class CustomViewFilter : IFilter
  {
    public const string BASE = "Base";
    public const string LAYOUTS = "Layouts";

    #region IFilter Members

    public bool Perform(ExecuteEnum exec, IRailsEngineContext context, Controller controller)
    {
      string customerId = context.Params["CustomerId"];
      return Perform(exec, context, controller, customerId);
    }

    #endregion

    public bool Perform(ExecuteEnum exec, IRailsEngineContext context, Controller controller, string customerId)
    {
      // Use the Base or Customer specific view
      string viewName = null;
      if( null != controller.SelectedViewName )
      {
        viewName = Path.Combine(BASE, controller.SelectedViewName);
        if( null != customerId )
        {
          string customerViewName = Path.Combine(customerId, controller.SelectedViewName);
          if( controller.HasTemplate(customerViewName) )
          {
            viewName = customerViewName;
          }
        }
      }
      controller.SelectedViewName = viewName;

      // Use the Base or Customer specific layout
      string layoutName = null;
      if( null != controller.LayoutName )
      {
        layoutName = Path.Combine(BASE, controller.LayoutName);
        if( null != customerId )
        {
          string customerLayoutName = Path.Combine(customerId, controller.LayoutName);
          string customerLayoutPath = Path.Combine(LAYOUTS, customerLayoutName);
          if (controller.HasTemplate(customerLayoutPath))
          {
            layoutName = customerLayoutName;
          }
        }
      }
      controller.LayoutName = layoutName;

      return true;
    }
  }
}

posted @ Thursday, June 21, 2007 4:33 PM


Print

Comments on this entry:

No comments posted yet.

Your comment:



 (will not be displayed)


 
 
 
Please add 1 and 3 and type the answer here:
 

Live Comment Preview:

 
«August»
SunMonTueWedThuFriSat
272829303112
3456789
10111213141516
17181920212223
24252627282930
31123456