Html.RenderAction for ASP.NET MVC 1.0

Please note that this post was migrated to my new blog platform. There may be bad formating, broken links, images, downloads and so on. If you need an item on this page, please contact me and I will do my best to get it from my backups.

~E

The ASP.NET MVC 1.0 Futures assembly (that is not included with ASP.NET MVC 1.0) has a powerful HtmlHelper extension method called RenderAction().   It sounds similar to the Html extension method called RenderPartial() for a good reason.  RenderAction() executes an action on a controller, allowing you to move your logic out of the views.

The problem with Html.RenderPartial()

There is no direct problem with this.  It is just that developers are left with only the ability to render a Partial View.  What if you want that partial view to act on model properties you pass into that partial view?  What if you need to access the ambient values in the Routes collection to render some specifics?  Unfortunately, developers are only left with RenderPartial() which only gives you access to a partial view.  If you really need this logic, you have no choice but to put it into the partial view.  Or, to put it into your controller’s action method that calls the view that calls the partialviews.  Needless to say, that’s a bit hokey.

What Html.RenderAction<TController>() Resolves

It gives you the power of moving that complex View and Partial View logic to a Controller’s Action, where it belongs!  Think of it as a “Render Partial Action” method of where you can call back into a controller to render some logic. This gives you the ability to clean up your partial views now by removing that logic and placing it on a controller’s action, that renders the partial view when done. The syntax looks like:

<% Html.RenderAction<ProductController>(c => c.RenderProductResults()); %>
<!– Or… //–>
<%= Html.RenderAction(“RenderPartialResults”, “Product”); %>

Put simply, this renders an action on a controller directly in your view.  You may be thinking “big deal”, but I assure you this is a big deal in large complex MVC sites.  Having the power to abstract or breakup your controller’s actions into multiple partial-actions and multiple views is very powerful.  Instead of relying on the 1 controller’ action to wire up all of the data for all of the views, partial views, and logic for the views.  Now, you can just focus on that one section - and abstract the rest into reusable parts.

You may be wondering where this extension method is with your ASP.NET MVC project.  As mentioned above, it is part of the Futures extension of the ASP.NET MVC project at codeplex.

ASP.NET MVC Sidebar Widget Example

The current pattern suggests you use Html.RenderPartial to render those partial views as your sidebar widgets.  What if you want those widgets to be more complex?  What if you want those widgets to act on the the current Route?  Well, you are left with little options with RenderPartial.  Instead, you want to use RenderAction to call an action on a controller to handle that logic. 

Assume we are viewing a blog post entry and on the right, we want a sidebar widget for related posts. To do this, first create an action on a controller called RelatedPosts().

public ActionResult RelatedPosts(Int32 postID)
{       
// some complex logic, or simple logic, can go here now…
//

if (postID < 1)
return PartialView(“NoRelatedPosts”);
  var relatedPosts =
    _postService.FetchRelatedPosts(postID);

  if (relatedPosts.Count > 0)
   return PartialView(“RelatedPosts”, relatedPosts);
  else
    return PartialView(“NoRelatedPosts”); }

Notice how the logic here accounts for empty or no results, and returns an a different partial view?  Using RenderPartial(), this is logic could only be reflected with inline IF ELSE brackets within your PartialView - and ugly spaghetti mess.  Also, how would you even retrieve the related posts collection?  You have no choice but to obtain that collection back on the post entry view action - which should not be concerned about our little sidebar widget.  All it should do is wire up the post.  But, that is not the case with RenderPartial() - you have to wire up all of your data ahead of time in one large ViewModel with multiple entities dangling off of it.

No no.  Let’s do it with RenderAction() and instead put this logic into the Controller (where it belongs, so we can test for it); and then, we can call it with the RenderAction() extension.  We can do this now with a simple call within our larger post view like so:

<% Html.RenderAction<PostController>(c => c.RelatedPosts(Model.PostID)); %> 

We instead kind of render a partial action by calling an action on a controller that handles the logic that we would otherwise have to put in the view.  Now, our main post view action doesn’t have to be concerned about wiring up our sidebar partial view.  We can just call RenderAction() in the view.

ASP.NET MVC AJAX Example using RenderAction

Taking an example from the book Profressional ASP.NET MVC 1.0, we’ll use the submitting a Form Using Ajax example to replace the limited RenderPartial() function with a richer RenderAction() from a Controller’s action to process the results more finely.

In the ProductController, you would add a new method with the signature RenderProductResults(IList<Product> products):

public ActionResult RenderProductResults(IList<Product> products)
{
    // insert some custom logic here, maybe even switch partial views, etc
    //
    if (products.Count > 0)
        return PartialView(“ProductSearchResults”, products);
    else
        return EmptyResult();
}    

Now, you can update their ajax example to render this new action instead of the RenderPartial() from their example:

<h1>Product Search - jQuery</h1>
<form action=”<%= Url.Action(“ProductSearch”) %>” method=”post” id=”jform”>

  <%= Html.TextBox(“query”, null, new { size=40 }) %>
  <input type=”submit” id=”jsubmit” value=”go” /> 

</form>

<div id=”results2”>
  <% Html.RenderAction<ProductController>(c => c.RenderProductResults(Model.Results)); %>
</div>

<script src=”/Scripts/jquery-1.3.2.js” type=”text/javascript”> </script>
<script src=”/Scripts/jquery-form.js” type=”text/javascript”> </script>
<script>
$(function() {
$(‘#jform’).submit(function(){
$(‘#jform’).ajaxSubmit({ target: ‘#results2’ });
return false;
});
});
</script>

Look for the Html.RenderAction line above.  What this does is instead of rendering a partial view in the id=”results2” location, you can now render a “partial Action” with the Html.RenderAction() call.  Notice that how we are also passing strongly typed parameters directly into the method?  Yep, fully supported.

By using the RenderAction instead of RenderPartial, you have much more control over what happens with that rendering of the partial (now, rendering of the action).  This gives you an excellent opportunity to remove that complex view logic you may have, and place it in an Action where it belongs!

Custom ViewEngines and Extensions

Now, you can also resolve this logic issue by creating custom ViewEngines, or extensions that expand upon the ViewEngine, HtmlHelper, or UrlHelper.  But, I see those methods as more application-wide common logic (like pagers and server controls for display name).  I do not see that as a solution for your one-off partial view for the ajax response to something.  Think of how bloated your ViewEngine would get, or how many different ViewEngines you’d have to choose from.  No, ViewEngine extensions have a place which I will post about as well.

Summary

When your views start getting complex and messy, it may be time to switch to a RenderAction to handle that logic.  I know I have cleaned up quite a lot using it.  Also, custom view engines have a place in their own right to abstract more global/common logic across the entire site.

Html.RenderAction for ASP.NET MVC 1.0

> Revision History
> About the author