How to generate just a portion of a view in an ASP.NET MVC 2.0 application
Sometimes it makes sense to use application logic to generate just a portion of a view in an MVC 2.0 application. This is most useful when you want to display dynamic information on a page that is unrelated to the other dynamic content on the page. In that case, the data you need for the portion of the view isn't part of the model. Maybe it comes from an entirely different source, such as stock or weather data on a page that displays store locations in a selected metro area. Or you might want to implement a navigation component on the page that has some kind of complicated logic to decide what options to display to a user at a particular point, maybe based on recent user actions or permissions. Or it could display a user's shopping cart contents as she navigates your product catalog. The possibilities are unlimited.
There are many scenarios when it is useful to be able to write application logic in the controller to generate the data and then inject the data into the response stream to the view, outside of the rendering of the HTML for the main portion of the page.
The RenderAction() helper method calls into a controller method, then injects the action method's output into the response stream. You can pass whatever parameters you want from the view to the action method in order to customize the response.
If you stop and think about this a bit, it might seem a bit strange. A view calling into a controller? Is a view supposed to even know about controllers? Well, views and controllers aren't entirely decoupled, maybe not as much as we would want them to be for purity's sake. A trivial example is when a view contains an ActionLink method call to produce a link into a controller action method. The view needs to know what action methods are available in order to create the link. That sort of thing doesn't include any application logic, however, so RenderAction is definitely a step up from this scenario.
But what is actually happening with RenderAction is that the view is asking the controller for data to display on the resulting web page. In a way, it is a variation of letting the controller provide a model to the view, except with RenderAction the view is making the request outside of the initial instantiation of the view.
Let's look at an example of how to use RenderAction. Let's say that you have an MVC application that collects and manages information about the dogs in a kennel. The Dog controller has an action method called RenderList. Imagine that this method does some sort of complicated process to extract some information outside the main scope of the application. We'll simulate that by using the dogs object already defined in the controller. Here is the action method that the main view will call using RenderAction:
// Used with RenderAction
The RenderList partial view, shown below, produces a bulleted list of dogs, using a DogInfo partial view. The code displays a header, then loops through the dog collection passed to it as the model by the RenderList action method above. This is the component that you can drop into any view in the application.
<h3>Render Dog List</h3>
<% foreach (var dog in Model)
<% Html.RenderPartial("DogInfo", dog); %></li>
<% \\} %>
The RenderList partial view generates the result of using RenderAction to call the RenderList action method.
The last piece of the solution is the action method and view that makes the call to the RenderList action method. This is the RenderActionView action method and its accompanying view. Below is the code for RenderActionView. Notice that it passes no ViewData or model to the view at all.
// The main view to display
And below is the RenderActionView view. Note that it has some static content, then calls RenderAction to drop the content generated by the RenderList action method into a particular location on the page. That call causes the RenderList action method to return a snippet of HTML to the view.
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<p>This view uses a RenderAction to display a list of dogs, using the RenderList partial view, which in turn uses the DogInfo partial view.</p>
<% Html.RenderAction("RenderList", "Dog"); %>
Figure 1 shows the result of running the application, which displays the dog list using RenderAction.
Figure 1: Results of application that generates a partial view using RenderAction
Let's recap what happens when the user clicks the link that executes the RenderActionView action method, /Dog/RenderActionView.
- The RenderActionView action method executes, which causes the RenderActionView view to load.
- The RenderActionView view begins rendering the page, and eventually gets to the RenderAction method call.
- RenderAction calls the RenderList action method in the Dog controller, which passes the dogs collection to the RenderList partial view.
- The RenderList partial view takes the dog data and generates a bulleted list of dogs, using the DogInfo partial view to generate the string information for each dog.
- The partial view generated from the RenderList action method is inserted into the stream of HTML in the RenderActionView view, and the list of dogs appears within the web page.
What's important here is not that the code uses nested partial views to generate content—although that is very cool and efficient—but that by using RenderAction you can insert content into a page. You're not limited to HTML either; you can insert almost any kind of content you want.
Use RenderAction with Care
RenderAction is a very powerful feature of MVC applications. But remember that with great power comes great responsibility. It is an easy feature to abuse and can easily result in a convoluted application with controllers and views calling each other in highly unmaintainable ways. So be careful with it! Use it where it makes sense, but nowhere else.