Here's the theory Mark.
The theme engine is part of the mvc framework. It's purpose is to build file paths and assemble the views. The only reason to derive a new view engine is when you need to change how the paths are constructed.
In your case, the path building process isn't being changed. Only the MasterView parameter is. Restricting and/or formatting this parameter is dependant on the application, and should therefore be handled within the application.
Having the view engine handle this forces an upwards dependancy from engine to application.
Now, you are right, the View() override I mentioned works fine by itself. However, in order for all the actions on each controller you have to take advantage of it, you would have to process the pageId in every action before returning the ViewResult.
By creating a base class for your controllers, and housing a method there, you eliminate repeated code.
public class BaseController
private IPageRepository _pageRepository;
protected BaseController(IPageRepository pageRepository)
_pageRepository = pageRepository;
protected ActionResult ThemedView(string pageId, Object viewObject)
// format pageId
if (pageId == null) pageId = pageRepository.HomeOrLowest();
// build masterView
string masterView = _pageRepository.ByStub(pageId);
// test masterView and display error if needed
if (masterView == null) return RedirectToAction("NotFound", "Error");
// if the above displays error, this will never be reached
// it does not need to be above the prior line of code
// also, should look into a base viewmodel to house this
ViewData["currentLink"] = pageId.Replace(" ", "-");
// return the view
return View(View.ViewName, masterView, viewObject);
public class MyController : BaseController
public MyController(IPageRepository pageRepository) : base(pageRepository)
public ActionResult Index(string pageId)
// optionally pass in a view model where null is
return ThemedView(pageId, null);
This is untested code! Make sure to test it!
You might even consider making an application service for the formatting of the pageId, to separate the concerns of formatting and processing even more clearly. But that's another post.