Introduction
In a typical ASP.NET MVC application, the controller sends model data to the view and the view then renders the data in the required form. In some cases, however, the view needs to display model data in different ways depending on some condition. This task can be done in the view itself or can be isolated in what is known as child action method. This article shows how child action methods can be used to render markup dynamically.
Child Action Methods and Their Use
Consider a case where you have data model based on the Customers table of Northwind database (see below).
Customers Table
Now assume that a controller action method retrieves a particular Customer object and sends it to the view. Once the view receives the data, it needs to display it in the required fashion. At times the way data is displayed is dependent on some condition. A straightforward approach is to place this logic in the view itself. However, adding this logic to the view will make it bulky. To avoid mixing of too much logic or processing in the view you can make use of child action methods.
A child action method is just like any other action method with a couple of differences:
- Unlike a normal action method you cannot invoke a child action method directly through a browser URL. A child action must be called by a view.
- A child action method is decorated with [ChildActionOnly] attribute.
A child action method typically returns an HTML markup but it can return any text data. There are two ways to return HTML markup from a child action method, viz. returning a Partial View or returning a string. In the following example, you will learn to use both of these approaches. Child action methods are also used with partial page output caching.
Controller Index() Action Method
Consider an action method residing in HomeController class as shown below:
public ActionResult Index() { NorthwindEntities db = new NorthwindEntities(); var data = (from item in db.Customers orderby item.CustomerID select item).Take(1); return View(data.SingleOrDefault()); }
The Index() action method shown above fetches a single Customer object and passes it to the view. Notice the use of the Take() method to select just one object. Also, notice the use of the SingleOrDefault() method while retrieving the Customer object from IQueryable type (data).
Creating a Child Action Method
Let’s assume that the Index view needs to display the Customer data passed to it differently, depending on whether a user is authenticated or not. If a user is authenticated the data is to be displayed in an HTML table in horizontal fashion (a single row). If a user is not authenticated the same data is to be displayed in vertical fashion (one column-multiple rows). This dynamic markup is generated inside a child action method – GetMarkup() as shown below:
[ChildActionOnly] public ActionResult GetMarkup(Customer obj) { string html = "<table border='1' cellpadding='3'>"; if (HttpContext.Request.IsAuthenticated) { html += string.Format("<tr><td>{0}</td><td>{1}</td><td>{2}</td><td>{3}</td></tr>", obj.CustomerID, obj.CompanyName, obj.ContactName, obj.Country); } else { html += string.Format("<tr><td>{0}</td></tr>", obj.CustomerID); html += string.Format("<tr><td>{0}</td></tr>", obj.CompanyName); html += string.Format("<tr><td>{0}</td></tr>", obj.ContactName); html += string.Format("<tr><td>{0}</td></tr>", obj.Country); } html += "</table>"; return Content(html, "text/html"); }
As you can see, the GetMarkup() method is decorated with the [ChildActionOnly] attribute. The GetMarkup() method accepts a Customer object and returns an ActionResult. Inside it checks whether a user is authenticated or not. This is done with the help of the IsAuthenticated property of the Request object. If a user is authenticated, an HTML table with a single row is formed and four properties of the Customer object, viz. CustomerID, CompanyName, ContactName, Country are populated in it. If a user is not authenticated a table with one column and four rows is created. Once the HTML markup for the table is ready it is sent to the caller using the Content() method. The Content() method accepts a string and content type and returns a ContentResult object. In this case content type is text/html.
In the above version of the GetMarkup() method you embedded the HTML markup in the method itself. If the markup is complex you may think of separating it in a Partial View. For example, you may add two partial views, viz. HorizontalMarkup.aspx and VerticalMarkup.aspx that contain the HTML markup for the horizontal and vertical table respectively. If you go by this approach you can modify the GetMarkup() method as follows:
[ChildActionOnly] public ActionResult GetMarkup(Customer obj) { if (HttpContext.Request.IsAuthenticated) { return PartialView("HorizontalMarkup", obj); } else { return PartialView("VerticalMarkup", obj); } }
As shown above the GetMarkup() method now returns a partial view using the PartialView() method. The first parameter of the PartialView() method is the name of the partial view and the second parameter is the data to be sent to the partial view. The partial views will contain the appropriate HTML markup. The markup of HorizontalMarkup partial view is shown below:
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<RenderActionDemo.Models.Customer>" %> <table border="1" cellpadding="3"> <tr> <td><%= Model.CustomerID %></td> <td><%= Model.CompanyName %></td> <td><%= Model.ContactName %></td> <td><%= Model.Country %></td> </tr> </table>
Calling a Child Action Method
Once you are ready with a child action method, you can call it from a view. You do this with the help of Html helper. There are two methods of the Html helper that allow you to call a child action method, viz. Action() and RenderAction(). Both – Action() as well as RenderAction() do the same task but there is a small difference in the way they function. The Action() method sends its return value to the calling view whereas RenderAction() method sends its return value to the response stream. The following markup uses Action() method to call GetMarkup() child action method.
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<RenderActionDemo.Models.Customer>" %> <!DOCTYPE html> <html> ... <body> <%= Html.Action("GetMarkup",Model) %> </body> </html>
The Action() method shown above takes two parameters – the name of the child action method (GetMarkup in this case) and an object representing data to be passed to the child action method (Customer object in this case). The following figure shows a sample run of the Index view when a user is not authenticated.
Index view when a user is not authenticated
Summary
At times you need to incorporate HTML markup in a view dynamically based on some condition. Child action methods provide a way to accomplish this task by isolating the logic from the view. A child action method is an action method that is marked with [ChildActionOnly] attribute and returns string data. A child action method can return markup as a string or partial view. Once created a child action method can be invoked from a view using Html helper methods Action() and RenderAction().
About the Author:
Bipin Joshi is a blogger and author who writes about apparently unrelated topics – Yoga & technology! A former Software Consultant and Trainer by profession, Bipin is programming since 1995 and is working with .NET framework ever since its inception. He has authored or co-authored half a dozen books and numerous articles on .NET technologies. He has also penned a few books on Yoga. Having embraced Yoga way of life he now writes about Yoga, life and technology on his website. He can also be reached there.