Sub-Controllers, PartialRequests and Separating Views From Controllers

Earlier, I blogged about an alternative to sub-controllers. That post wasn’t about sub-controllers being rubbish, rather that the problem I was trying to solve wasn’t the same as the problem that sub-controllers were meant to solve.

Recently, I’ve been looking at another problem in my code: all the stuff that has to appear on every page. Currently this is confined mostly to the login box that appears on the top right. When you’re not authenticated, it shows as a login form. When you are authenticated, it displays who you’re logged in as and gives you a logout link.

As this appears on every page, it’s defined in the master page and every controller has to return a model with the appropriate data in it. My post on DRYing out my unit tests showed one aspect of my solution to this. I defined a MasterPageData class that held all the models required for the master page to work, and derived from this a PageData<TModel> that also supplied a model that the page worked on. All my views were then able to access the (strongly-typed) model and the master page could access all the information (also strongly-typed) it needed too.

That just left how to populate the data. To do this, I defined two overloads of a new method JkhubView() in my base controller to be used in place of View(), one that took no arguments and returned a ViewResult<MasterPageData>, the other was a generic method that took a TModel and returned a ViewResult<PageData<TModel>>. Both of these methods populated the data in the MasterPageData object with the appropriate information.

This works. Every controller action calls one of the overloads of the JkhubView method and the strongly typed master page gets the data it needs. However, it’s not great for the following reason:

Every controller action makes an assumption about the view that will render its result.

That is, it assumes that the view will require this data about whether the user is logged in or not. This is completely irrelevant to a controller action that, for example, generates a list of a user’s projects. I’m keen to get the separation of controllers and views right. What’s the point in using an MVC framework if you’re going to mash everything up together anyway? I’ve pondered the question of what belongs in the controller and what belongs in the view before.

When I had decided that this just wasn’t the right thing for the controller to be concerned about, I decided to have an investigate of sub-controllers. I got the MVC Contrib project hooked up to my application, re-read Matt Hinze’s blog post on the subject and started creating my sub controller and view for the session status. Great, this is gonna be cool. Right then, let’s wire this up to my pages: all I need to do is… wait, I pass the sub-controller to my controller action to place it in the ViewData?

Okay, first off, I don’t like using the ViewData. I much prefer a strongly typed model to give me everything I need (that’s why I’ve got the MasterPageData class floating about). So that’s a bit sucky.

But more than that. The controller action is still making that same assumption about what the view is going to need. Sucky.

Okay, not to worry, I recall reading about an alternative approach to this problem. Steve Sanderson posted a neat little trick to fire off another request to the MVC pipeline. The only problem with his implementation is that his controllers are creating the PartialRequest and stuffing it in the ViewData again. Those were my two sticking points with sub-controllers! However, a quick modification to the HtmlHelper extension he suggests allows the View to create the PartialRequest inline:

public static void RenderPartialRequest(this HtmlHelper helper, string controller, string action)
{
	PartialRequest request = new PartialRequest(new { controller, action });
	request.Invoke(helper.ViewContext);
}

Instead of passing the ViewData’s key, we tell the extension method which Controller and Action to create the request for. I’ve not yet found any downsides to this over creating the PartialRequest in the controller. I may find some issues when I come to look at the partial output caching that Steve blogs about in his next post, so as with all things I’m building here, this advice is subject to change without warning.

About these ads

3 Responses to Sub-Controllers, PartialRequests and Separating Views From Controllers

  1. [...] need to access the HttpContext for is to get the authenticated user, as I was talking about in my last post. I ended up with my SessionController looking like [...]

  2. Steve says:

    Interesting, but now your view is using the name of a controller… essentially calling a controller. Seems to violate MVC, but I guess its borderline. Just a thought. If you have found any additional approaches, I’d be interested in hearing them.

  3. Giraffe says:

    Good point, Steve. I definitely thinks it’s a step forward from the Controller assuming the View cares about this data in this situation. I don’t know whether I stressed it enough in the original article, but this thinking applies specifically to where we’re talking about data that is orthogonal to the intent of the page. I think a good indicator of where this works well is when you’re rendering something in the Master Page.

    I’m not sure how serious a transgression of SoC I feel this is, given that Views can use Html.ActionLink, specifying a controller and action to render the link for, and no-one bats an eyelid at that.

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

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: