The Filter-ViewData anti-pattern

In just about every website you go to these days, its layout follows a very similar pattern:

image

You have some static resource logo, a large main section with information that our controller action supplies.  But we also have some other stuff, those green sections.  Things like breadcrumbs, shopping carts, login widgets, smart menus and so on.  It’s all still data driven, but its information has absolutely nothing to do with what’s going on in my main section.  This is some of the first kinds of duplication we see in MVC applications – common, data-driven sections across many pages in our application.

The usual way to get rid of this duplication is through ActionFilters.  We decorate our main section action with filters:

public class ProductController : Controller
{
    [LoginInfo]
    public ActionResult Index()
    {
        var products = _productRepository.FindAll();

        return View(products);
    }

We don’t have that duplicated login information code in all of our controllers, and we can even go so far as to decorating our controller class or layer supertype to apply our filter to a broad set of controllers.  But looking at our filter, it looks like we took a step backwards:

public class LoginInfoAttribute : ActionFilterAttribute
{
    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        var currentUser = _userSession.GetCurrentUser();

        filterContext.Controller.ViewData.Add("currentUser", currentUser);
    }

Back again to magic strings!  With MVC Contrib, it looks a little better as we can skip the key part, and just pass the current user object in.  But beyond the magic strings issue here is the problem of linking what is essentially a view concern (how I organize the different pieces of information on a given page) with my controller structure.  What if that widget isn’t shown on all actions for a controller?  What if I have four widgets, and not all are shown on every screen?  It begins to break down the normal, filters-on-layersupertypes-pattern.  I’d rather not let my view structure, with master pages and what not, influence my main-line controller design in any way.

The other issue I run into is figuring out where the heck the information comes from if I’m looking at a view.  I see a piece being pulled out of ViewData, but not any clear indication of where that information came from:

    <% Html.RenderPartial("loginView", ViewData["currentUser"]); %>

    <h2>View Products</h2>

Yes, we can put this in a master page.  But now we’ve coupled the requirements of our view structure with the structure of our controllers, not always a good thing.  In my (not-so) humble opinion, an action should be responsible for generating exactly one model.  Things like action filters fiddling with view data are three layers of indirection to get around this rule.  But in the MVC Futures assembly, we have a different option.

Tangential concerns with RenderAction

In our original view, if we dissected each piece, we had a main section and other, orthogonal sections.  The main section’s information is handled by our main action handling the request.  The other pieces are needed, but those concerns aren’t really related to the main section.  Does showing a login widget have anything to do with showing a product list?  No.  But I don’t want to couple all the different concerns in completed view with the main action.  Because those widgets, and where they’re located is a view concern, we can initiate the rendering of those pieces from the view using RenderAction.

RenderAction works like a mini-request, exercising the MvcHandler, but re-using the existing HttpContext.  It simulates a request, but writes out to the exact same response stream, at the exact right place:

image

Our view doesn’t look much different, it looks like a cross between a Url.Action call and RenderPartial:

    <% Html.RenderAction<LoginController>(c => c.Widget()); %>

    <h2>View Products</h2>

What you don’t see is any data or model passed to RenderAction.  The LoginController is a plain controller, with a regular action on it.  The action now can be concerned with both finding the data for the model and choosing the view to render:

public class LoginController : Controller
{
    public ViewResult Widget()
    {
        var currentUser = _userSession.GetCurrentUser();

        return View(currentUser);
    }

I don’t have to jump through hoops to find where my information came from, as I only need to follow the link from the RenderAction call to the Widget action method.  Additionally, my original ProductController now has absolutely zero logic for all of the orthogonal concerns, whether it’s hidden in an action filter or not.  For each view, I can decide what master page to use, and place those RenderAction calls there.  I let my view decide what layout is correct.

Wherever I see action filters poking around with ViewData, I see a very clear path to using RenderAction instead.  It’s a much more cohesive and flexible model, and straightforward to understand where each individual piece comes from.  Controllers have enough responsibility as it is, why do they need to be burdened with the additional responsibility of organizing data for tangential concerns?  RenderAction has zero performance penalty, as it’s not a real, external request.  ViewData can be abused as a bag-o’-stuff for views to consume, but that won’t lead to maintainable, understandable markup.  Instead, we can utilize the RenderAction method and create very cohesive controllers and strongly-typed views, with explicit concerns.

Related Articles:

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Jimmy Bogard

I'm a technical architect with Headspring in Austin, TX. I focus on DDD, distributed systems, and any other acronym-centric design/architecture/methodology. I created AutoMapper and am a co-author of the ASP.NET MVC in Action books.
This entry was posted in ASP.NET MVC. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Jason Meckley

    isn’t this very similar to ViewComponent in Monorail?

  • http://chadly.net Chad Lee

    I totally agree. Like Jason said, this is exactly the scenario a Monorail ViewComponent supports. Except ViewComponents allow things like sections which allows the calling view to customize the rendering of the component.

    It is a shame that there is no concept of ViewComponents or even the RenderAction method in the core asp.net mvc release.

  • http://www.sullivansoftdev.com/blog Brian Sullivan

    I really like RenderAction as well. I posted something about it last year here: http://www.sullivansoftdev.com/blog/?p=12

    You’ve done a much better job, though, of explaining the need for this feature. I hope that this makes its way from the Futures assembly to the canonical product eventually.

    What do think about reservations that have been expressed about this violating the MVC pattern? (See Phil Haack’s post: http://haacked.com/archive/2008/07/16/aspnetmvc-codeplex-preview4.aspx. Note that this is from almost a year ago.)

  • mogadanez

    what about perfomance?

    does RenderAction is slower than RenderPartial?

    for example if i have Items List and each Item rendered By RenderAction ?

  • http://dalager.com Christian Dalager

    An important thing to remember when using RenderAction is that it because it uses the current request context you might get some strange side effects if you don’t use the Post-Redirect-Get pattern with your actions.

    Rendering a View directly from within a POST action will cause the target of your RenderAction within that view to be executed with same context.

    If you post a string with html in it, you will not only need to set the [ValidateInput] property on you post-action but also on your RenderAction target action.

    You could argue, that in that regard RenderAction is broken, but if you just know how it works, it’s easy to get around it :)

  • http://www.lostechies.com/members/bogardj/default.aspx bogardj

    @Chad, Jason

    Yeah, it’s very similar to ViewComponents. Feels like the WebForms view engine got left behind in the last few years…

    @Brian

    As for violations of the pattern…I don’t see how filters used for view data isn’t a violation, you’re now strongly coupling controllers and views.

    @Mogadanez

    No idea. But the scenario you mention isn’t valid, you can’t pass data down to RenderAction (which is the point, it’s supposed to be independent). Your example is a textbook case of using RenderPartial.

    @Christian

    I would like actions with RenderAction to be treated differently than everything else for that reason. I also don’t want people to be able to get to those routes directly from a URL.

  • http://sampy.com Mike Sampson (Sampy)

    RE: Pattern Violation

    If you have a way to attach filters to an action method and/or controller that is independant of the class itself (ie not using attributes) I think you can use filters but not suffer the problem of having the view layer “reach back” and drive the controller layer.

    I’ve struggled with this a lot myself and I’ve found that overrided GetFilters on your ControllerActionInvoker and getting them from some sort of registry allows clean composibilty with out having your controllers dependent on your views. I designed a system that was built on something similar to RenderAction but abandonded it because I didn’t like the idea of my views calling controllers.

    You can see my implementation of this in Oxite. FubuMVC does something very similar.

  • http://www.lostechies.com/members/bogardj/default.aspx bogardj

    @Mike

    Why is a view calling a controller a pattern violation? If you have an IMG tag in your page, that’s a view making another request back to the server for content. Instead of thinking of it as “calling back into the controller layer”, I view RenderAction as making a new _internal_ request for view content. It just happens to be internal, rather than external.

  • moganez

    @bogardi

    i Have list with complex view.
    with many and many variats.

    very simlify


    ${item.Name}



    so if i use renderPartial, i need create a BIG, COMPLEX, viewdata. and it is not reusable with one item view action

  • http://www.lostechies.com/members/bogardj/default.aspx bogardj

    @moganez

    Why can’t you pass down the “item” down to RenderPartial? We do this all the time, breaking our model into individual components rendered by strongly-typed views and partials.

  • http://www.dieajax.com David Miles

    RE: Pattern Violation

    I’m still with Mike “Sampy” Sampson on this, and not quite convinced by the IMG tag example. In the case of a browser making a request based on an IMG tag URL, it’s still executing the routing logic on the server. By putting a direct reference to the LoginController in your view, you’ve sort of “hardcoded” routing logic right in the view which doesn’t quite “feel” right. I think it’s closer than filtering, though.

  • http://www.lostechies.com/members/bogardj/default.aspx bogardj

    @David

    Since I’m creating links based on controllers (strongly-typed Url.Action), for me it’s no big stretch. I understand those that are more route-centric it’s a bit of a compromise. At its base, RenderAction renders a route, and you’re not forced to use the controller/action based version.

    I imagine it as something like the chain of responsibility pattern – multiple controllers get a “crack” at a request, shaped by a view (since this is how we ultimately determine what HTML gets down to the client).

  • http://sasani sasan

    good

  • E

    Thank you for this article!

    I have a question:

    Where will you preserve “global” variables such as CurrentUser, UserScore, IsAdmin, CurrentTheme etc.?

    Do you include it in every ViewData class that you need it in?
    Or do you create a BaseViewData class and let all the ViewData classes inherit from? And if so, where do you fill these variables? In every action, action filter or on BaseController’s OnActionExecuted?

  • E

    And another question:

    How do you pass another complex ViewData to a child partial?

    Do you hold nested view data objects?

    For example, a blog’s post list page:

    PostListViewData contains IEnumerable or IEnumerable ?

    The idea is to be able to have in Post.ascx more than a Post in some cases, and properties that aren’t in the Post domain object.
    If IEnumerable is used, then is it OK to instantiate PostViewData on the List.aspx?

    For example:
    < %
    foreach (Post p in Model.Posts) {
    Html.RenderPartial("Post",new PostViewData { Post=p,SomeOtherThing=someOtherThing });
    }
    %>

    Thanks!

  • http://www.lostechies.com/members/bogardj/default.aspx bogardj

    @E

    First question – RenderPartial on all accounts. If the data is completely orthogonal, RenderPartial.

    Second question, for child partials, it’s mapped on the parent to be the child type.

    So,

    OrderDto contains a list of OrderLineDto, and I have a partial for both OrderDto and OrderLineDto. Make sense?

  • E

    @bogardj

    Thank you.

    I couldn’t understand your first answer. For example, I have a Post.ascx and in which, I want to put “Edit” link if the Post’s creator is the current user.
    Where from should I bring the CurrentUser?

    For the second answer – Thanks, makes sense.

  • mogadanez

    about performance:
    i make simple test shown that RenderAction and RenderPartial are very close by execution time.

    http://mogadanez.blogspot.com/2009/07/aspnet-mvc-speed-test.html