Partial Requests in ASP.NET MVC
ASP.NET, MVC, UI October 14th, 2008In your ASP.NET MVC application, it can be tricky to combine multiple independent “widgets” on the same page. That’s because a WebForms-style hierarchy of independent controls clashes awkwardly against a purist’s one-way MVC pipeline. Widgets? I’m taking about that drill-down navigation widget you want in your sidebar, or the “most recent forum posts” widget you’d put in the page footer. Things that need to fetch their own data independently of the page that hosts them.
So, you’ve got basically two options:
- Make sure each action prepares an absolutely complete set of ViewData for not just the main page you’re rendering but also for every widget it hosts. Then in your view you can render widgets by calling <% Html.RenderPartial(…) %>, passing to the partial view template the subset of ViewData needed to render that widget.
- Allow actions or views to invoke other actions, spinning off multiple internal mini-MVC pipelines that prepare and render each widget.
Incidentally, this is exactly the same choice on offer to Ruby on Rails developers, who face the exact same issue. However, in Rails-world, option 2 is frowned upon because of the framework’s performance issues. But we don’t need to have that problem in ASP.NET MVC.
These two options are both perfectly usable in ASP.NET MVC, and each has its strengths and is suited to different circumstances.
Option 1 keeps your MVC pipeline simple and elegant, but it struggles to scale up in complexity if you have many widgets or hierarchies of widgets that appear or disappear at different times. It’s nice to use filter attributes to inject the ViewData elements needed for each widget, but not nice if there are many.
Option 2 is conceptually much simpler and enables simpler code, though at runtime there are more moving parts. It’s more like having a collection of genuinely independent widgets. This is what you get with <%= Html.RenderAction(…) %> (which is sadly relegated to the MVC Futures assembly and has been left with some technical problems), and also with MvcContrib’s new idea of subcontrollers.
You’re free to choose the option that works best for you in any individual case. If someone tells you that internal subrequests (option 2) are bad because it “isn’t MVC”, then just bite them on the face immediately. Also ask them why they’re still willing to use Ajax, and even <IMG> tags for that matter, given that both are a form of subrequest.
About subcontrollers
Firstly, thankyou to the MVC Contrib guys, because the subcontrollers idea is neat and genuinely improves on what we had before with Html.RenderAction().
The core idea of subcontrollers is putting into ViewData a delegate for each widget. The view can render the widget by invoking the delegate. This allows the view to be totally ignorant of the widget it’s rendering, leaving the controller in full control. That eliminates the main problem people had with Html.RenderAction(). Brilliant!
What I don’t like so much about MVC Contrib’s subcontrollers is that it’s quite a heavyweight and complex solution. Firstly you have to be using MVC Contrib, and then you have to learn a non-obvious set of new conventions, and an alternative controller base class, and do something funny with your default model binder. I think it’s possible to get virtually all the same benefits (and some extra ones) with a utility class that’s just 17 lines long.
Partial Requests are easy
You’ve heard of partial views, so how about partial requests? Within any MVC request, you can set up a collection of internal partial requests, each of which can set up its own internal partial requests and so on. Each partial request renders a plain old action method in any of your plain regular controllers, and each can produce an independent widget. I’m calling them partial “requests” rather than “controllers” because they run a proper MVC request-handling pipeline that’s compatible with your routing system and your controller factory. Still, as with subcontrollers, all the control remains in controllers, and the view can be ignorant.
Drop this class somewhere in your MVC project:
public class PartialRequest { public RouteValueDictionary RouteValues { get; private set; } public PartialRequest(object routeValues) { RouteValues = new RouteValueDictionary(routeValues); } public void Invoke(ControllerContext context) { RouteData rd = new RouteData(context.RouteData.Route, context.RouteData.RouteHandler); foreach (var pair in RouteValues) rd.Values.Add(pair.Key, pair.Value); IHttpHandler handler = new MvcHandler(new RequestContext(context.HttpContext, rd)); handler.ProcessRequest(System.Web.HttpContext.Current); } }
Now, when you want to attach a widget to your output, you can put a partial request into view data as so:
ViewData["latestPosts"] = new PartialRequest(new { controller = "Blog", action = "LatestPosts" });
… then wherever you want to display that widget in your view, put:
<% ((PartialRequest)ViewData["partialAction"]).Invoke(ViewContext); %>
… or if you prefer, use this trivial Html.RenderPartialRequest() helper:
public static class PartialRequestsExtensions { public static void RenderPartialRequest(this HtmlHelper html, string viewDataKey) { PartialRequest partial = html.ViewContext.ViewData.Eval(viewDataKey) as PartialRequest; if (partial != null) partial.Invoke(html.ViewContext); } }
Now, having imported the relevant namespace, your view can simply contain:
<% Html.RenderPartialRequest("latestPosts"); %>
Assuming you have a regular BlogController with an action called LatestPosts, which might render its own view (have it render an MVC View User Control rather than an entire MVC View Page) or might simply return a ContentResult, you’ll find that its output is injected at the appropriate point in your view.
Of course, this works seamlessly with whatever arrangement of controller factories, model binders, and action invokers you might be using, and it executes any filters that surround the partial request’s target action method.
It’s testable, too: your unit tests can pick the PartialRequest object out of ViewData, and inspect its RouteValues collection, so check it’s invoking the expected target.
It naturally supports hierarchies of widgets, too: the action that a PartialRequest calls can fill its own independent ViewData collection with other PartialRequest objects, and invoke them from its own view, and so on.
It works well with Ajax, too: since your widget is the output of a plain old action method, you could use an Ajax request to re-fetch the widget’s contents and update it in the DOM without a full page refresh.
There’s one other major benefit, too, but I’m going to save that until tomorrow, because it’s cool enough to warrant a follow-up post in its own right…


October 14th, 2008 at 11:32 am
Steve, thank you this was a good read and something I will include in my own project to replace the RenderAction extension method (and in favour of the subcontroller support on MVCContrib).
October 14th, 2008 at 12:00 pm
Oh one thing that this doesn’t do it to play nice if placed on a master page. I imagine quite a lot of widgets would be placed on your master page and would need to be populated with different pieces of (typed) data.
You can do this with Html.RenderAction and my first thought was to just add an overload for the RenderPartialRequest extensions method where the second parameter was a PartialRequest.
However this won’t work since you will be invoking it in the wrong controller context, i.e imagine you paced the “recent post” widget on your master page then you’d need to be on view which was created by the Blog controller or controllerContext would be wrong and the action wouldn’t be able to be found¨.
October 14th, 2008 at 12:31 pm
Hi Andreas, thanks for your comments. I’m not completely certain that I understand what you’re getting at, but PartialRequest objects are able to target actions on any controller, independently of the main controller that’s handling the request. So I’m not sure there is an issue as you describe.
The tricky bit with widgets on master pages - and this applies equally to PartialRequest, MVC Contrib’s subcontrollers, and plain partial views as widgets - is deciding where to put the code that populates ViewData. That’s because ASP.NET MVC doesn’t have a specific concept of “master controller”, but instead wisely lets you pick your own. Your options are:
[1] Have a common base class for all your controllers, and override OnResultExecuting, putting a PartialRequest into ViewData there
[2] Have a filter attribute you can sprinkle over your controllers that puts a PartialRequest in ViewData
[3] Establish some other convention of master controller code in your app
Essentially, you’re forced to choose *somewhere* to prepare ViewData for master page widgets. The only obvious way of bypassing this is to use Html.RenderAction(), which allows the view to make its own decisions about rendering widgets. In many ways this is the cleanest solution of all. You might think this gives too much responsibility to the view, but we’re usually talking only about a few widgets on a single master page that applies to your entire application, so it certainly doesn’t reduce maintainability or testability unless you use and abuse it to excess.
October 14th, 2008 at 1:16 pm
Oh nevermind me. I just noticed I had swapped two variables around in my code and after solving that I was able to use the PartialRequest just fine from my master page.
The only modifications I made was to the extension methods
public static void RenderPartialRequest(this HtmlHelper html, string viewDataKey)
{
PartialRequest partial =
html.ViewContext.ViewData.Eval(viewDataKey) as PartialRequest;
PartialRequestsExtensions.RenderPartialRequest(html, partial);
}
public static void RenderPartialRequest(this HtmlHelper html, PartialRequest partial)
{
if (partial != null)
{
partial.Invoke(html.ViewContext);
}
}
and then you can call it by explicitly passing it a PartialRequest object like so
Html.RenderPartialRequest(new PartialRequest(new
{
controller = “YourController”,
action = “YourAction”
}));
Voliá
October 14th, 2008 at 1:21 pm
Hi there. Glad you got that sorted out. Obviously the way you’re using PartialRequest is exactly equivalent to using Html.RenderAction() (so you might was well use Html.RenderAction()), but if that’s what you want then fine.
October 14th, 2008 at 1:33 pm
@Steve well with the help of the two extension method overloads I will be able to use PartialRequests both ways using only one technique (also with potentially one less dependency in the future).
October 14th, 2008 at 1:35 pm
Hey, great! Can you also address possible downsides, because each time partials or components for ASP.NET MVC are discussed it seems that there is never a solution without downsides. Which is probably why the current Microsoft implementation is in ‘futures’…
Looking forward to the next post, and to using your simple implementation!
October 15th, 2008 at 6:46 pm
[…] whatever ordered set of filters you’ve using). And if you’re using something like the PartialRequest system for widgets that I described yesterday, it will naturally let you cache PartialRequests’ output separately from the actions that […]
October 15th, 2008 at 7:10 pm
@Mike: Thanks!
One caveat that I forgot to bring up is that, because of a quirk of how TempData is implemented, you can’t use TempData during an action that’s invoked via a PartialRequest. This isn’t really a concern for me in my particular use case right now, but I’m sure it could be resolved if anyone needed.
Other than that, I wouldn’t really say there are any particular downsides; after all, this is just one more technique to have in your toolbox. It’s not always the best approach. For example, if your widget is logically related to its host page, then it makes sense to prepare the widget’s viewdata inline in the host action and render the widget as a simple partial view. However, if the widget isn’t logically related to the host page, you might prefer not to mix those concerns and to use PartialRequest or subcontroller or Html.RenderAction() instead.
October 15th, 2008 at 7:32 pm
Thanks for the reply!
October 19th, 2008 at 3:40 pm
[…] Partial Requests in ASP.NET MVC […]
October 20th, 2008 at 6:35 pm
Very cool, and thanks for the link.
What’s the testing story for this technique?
October 20th, 2008 at 6:36 pm
Nevermind, I hadn’t read that paragraph. I will try this out now! Thanks.
October 21st, 2008 at 3:41 am
Great post. There seems to be a lot of work in the framework to prevent people from doing stuff like this for patterns sake. Partial rendering has been locked out from the beginning, it seems. I like taking the shackles off, and this code lets me do that.
Thanks for taking the time to post,
Jesse Foster | jf26028
October 22nd, 2008 at 1:31 am
Steve, again - well done. Wish I had thought of this. How about a filter attribute that inserts the PartialRequest into ViewData? Might help clean up the actions and ease testing. We have “portal” views which use 10 or more partials.
Also - have you considered contributing this to MvcContrib? It’s a very elegant solution.
October 22nd, 2008 at 7:58 am
This is great. I added little helper function to make this little bit more convient to use like
Html.RenderPartialRequest(new {controller=”Model”, action=”Panel_AddProfile” });
public static void RenderPartialRequest(this HtmlHelper html, object routeValues)
{
PartialRequest partial = new PartialRequest(routeValues);
if (partial != null)
partial.Invoke(html.ViewContext);
}
thanx
October 22nd, 2008 at 8:05 am
@Matt - thank you. I agree that if you are reusing widgets on whole sets of action methods, then it’s neat to use a filter attribute to put a PartialRequest object into ViewData. If you’d like to add partial requests and related code to MvcContrib then I’m entirely happy with that - please feel free to go ahead!
@Lauri - very nice. You should bear in mind that, as with Andreas’s comment earlier, what you’re doing with your overload is exactly equivalent to what the built-in Html.RenderAction() helper (or Html.RenderRoute()) does. So, you might consider using one of those built-in methods to achieve the same thing.
October 23rd, 2008 at 7:14 am
Hi Steve,
This is great!
I’ve implemented this solution in my small framework I am building, only I took a lambdier approach
You see, I am prohibiting the use of ViewData as Dictionary and setting the convention that Model must always be used (actually this convention is Jeremy Miller’s idea, but I found it very neat).
Now, in my controllers I do:
var viewModel = new ListUsersViewModel {
Sidebar = PartialFor<SidebarController>(c => c.List())
}
and in my view (because of the mentioned convention above), I can:
< %= RenderPartialOf(model => model.Sidebar) %>
much cleaner in my opinion!
Also as my delegate definition for above RenderPartial is:
public delegate PartialRequest PartialRequestOperation(T declaringType);
in my intellisense only the PartialRequest types in my model will show or can be used (no typos or wrong property selections).
What do you think?
October 23rd, 2008 at 9:18 am
Hi Vladan,
That looks nice - certainly there are some benefits to strongly-typed viewdata.
However, if you prohibit the use of viewdata as a dictionary, how will you mix in widgets that are unrelated to the current action? Are you going to force every action method to be aware of the notion of “sidebar”, as in the code you posted? And if so, why bother with PartialRequest at all? You could just put some SidebarData into your ViewData and then render the sidebar using a normal partial view (i.e., Html.RenderPartial()).
Update: Vladan has explained to me that he has a base class for all his ViewData model objects, and he uses a filter or controller base class to populate the “Sidebar” property on the ViewData model base class. That means he doesn’t need to mix the concerns of each widget in with each action. The main benefit of using PartialRequest here, then, is partial caching and the ability to change which widget gets rendered at runtime according to other data.
October 27th, 2008 at 3:55 pm
Isn’t it the same code RenderAction implemented? Would you point me the differences?
October 27th, 2008 at 4:30 pm
@Alice, yes, it’s very similar to Html.RenderAction(). The only difference is that with PartialRequest, the view template can be completely ignorant of the widget it’s being asked to render. This gives your controllers more control over the page output.
In some cases, this might not really make any difference. However, if you need to select and display a collection of widgets according to some logic, then it’s preferable to keep this logic in controller code rather than in a view template.
November 7th, 2008 at 10:12 pm
Can you show me what a test for Invoke method would look like using Rhino Mocks. I can’t get System.Web.HttpContext.Current to mock out.
Thanks
November 8th, 2008 at 10:07 am
@Peter - you don’t need to write tests for PartialRequest.Invoke(); you only need to write tests for your own action methods. If an action method is supposed to prepare a PartialRequest object, then your unit test can inspect ViewData and see that the expected PartialRequest object was put there. You don’t need to use any mocking tool to do this.
This is the strength of the whole ActionResult concept. It eliminates the need for mocking most of the time.
November 9th, 2008 at 5:35 am
Steve,
Congrats for this great work.
Great solution for Partial Requests in ASP.NET MVC. It is a better solution than sub controller of MVCContrib.
November 10th, 2008 at 3:08 pm
Steve- I understand that you can use ActionResult to test the output from PartialRequest.Invoke. In my scenario, I am putting PartialRequest.Invoke in a class library that I will use with a lot of MVC projects, and I need to include unit tests with this library, would a proper way to test Invoke method is still through examining ViewData object?
November 10th, 2008 at 3:41 pm
Peter - aha, I see. I’m not convinced that retrofitting a test for this is going to improve your code quality, but if you do want to break the dependency on System.Web.HttpContext.Current, try replacing the whole PartialRequest class with this:
public class PartialRequest
{
public RouteValueDictionary RouteValues { get; private set; }
public PartialRequest(object routeValues)
{
RouteValues = new RouteValueDictionary(routeValues);
}
public void Invoke(ControllerContext context)
{
RouteData rd = new RouteData(context.RouteData.Route, context.RouteData.RouteHandler);
foreach (var pair in RouteValues)
rd.Values.Add(pair.Key, pair.Value);
var handler = new AccessibleMvcHandler(new RequestContext(context.HttpContext, rd));
handler.ProcessRequest(context.HttpContext);
}
private class AccessibleMvcHandler : MvcHandler
{
public AccessibleMvcHandler(RequestContext requestContext) : base(requestContext) {}
public new void ProcessRequest(HttpContextBase httpContext) { base.ProcessRequest(httpContext); }
}
}
Note that to write a working unit test for Invoke(), you’ll also need to assign a mock IControllerFactory to ControllerBuilder (you’ll see when you try it).
November 18th, 2008 at 12:46 pm
Perfect! This looks exactly like what I need. Any chance you already have a simple VS solution you can zip up and send me?