When I was writing applications in WebForms (which, thankfully, I no longer do) I often ended up used .ascx files, commonly known as User Controls. Once I moved to MVC, I had to get used to a similar (though not the same) concept: Partial Views.

In this tutorial, we'll walk through a use case for Partial Views and explain what they are and why we need to use them. We'll also walk through the two different render methods: @Html.Partial() and @Html.RenderPartial() and discuss how they are different. Let's get started!

What are Partial Views?

Partial views are .cshtml views that are meant to represent portions of a page that can be used on multiple other views. They are roughly analogous to WebForms' User Controls, but not exactly, mostly because (just like all other views) they don't have a code-behind file.

When you create a partial view, the reason for it to exist is normally that it will be used on many other "parent" views. Let's set up a scenario for this.

Entrees and Ingredients

Say I want to display a list of entrees that I can make for dinner, and along with these entrees I'd like to display the ingredients necessary to make them. In order to do this, I might create classes for Entree and Ingredient like so:

public class Entree  
{
    public int ID { get; set; }
    public string Name { get; set; }
    public List<Ingredient> Ingredients { get; set; }

    public Entree()
    {
        Ingredients = new List<Ingredient>();
    }
}

public class Ingredient  
{
    public string Name { get; set; }
    public decimal Amount { get; set; }
    public string Unit { get; set; }
}

I want to create two views for this: an Index view that will display all the entrees and a Details that will just display one. On each of these views will need to be a list of ingredients, with their units and amounts. Because that display is the same on each view, we can turn that display into a partial view. In our particular case, our partial view will need to have a model bound to it, since it will be displaying the ingredients; of course, it's entirely possible to not use a model on a partial view.

Our partial view (let's call it Ingredients.cshtml) will look like this:

@model List<PartialViewsDemo.Models.Ingredient>

@{
    string display = "";
    foreach (var ingredient in Model)
    {
        display += ingredient.Name + " (" + ingredient.Amount.ToString() + " " + ingredient.Unit + "), ";
    }
    display = display.Remove(display.LastIndexOf(","));
}

<span>@display</span>  

Because this is a partial view, MVC expects it to exist in the Views/Shared folder:

A snapshot of the Views/Shared folder, showing that the Ingredients.cshtml file exists there

Now that we've got our partial view defined, we can define the Entree controller and the Index and Details actions and views. First, here's the Entree controller:

public class EntreeController : Controller  
{
    [HttpGet]
    public ActionResult Index()
    {
        var entrees = EntreeManager.GetAll();
        return View(entrees);
    }

    [HttpGet]
    public ActionResult Details(int id)
    {
        try
        {
            var entree = EntreeManager.GetAll().First(x => x.ID == id);
            return View(entree);
        }
        catch(Exception ex)
        {
            TempData["ErrorMessage"] = "No Entree with ID " + id.ToString() + " exists.";
            return RedirectToAction("Index");
        }
    }
}

In order to use the partial view Ingredients on the Index.cshtml view, we make a call to @Html.Partial(), as shown in the view below:

@model List<PartialViewsDemo.Models.Entree>

@{
    ViewBag.Title = "Index";
}

<h2>All Entrees</h2>

@if(TempData["ErrorMessage"] != null)
{
    <span>@TempData["ErrorMessage"]</span>
}

<table>  
    <thead>
        <tr>
            <th>
                Name
            </th>
            <th>
                Ingredients
            </th>
        </tr>
    </thead>
    <tbody>
        @foreach(var entree in Model)
        {
            <tr>
                <td>
                    @Html.ActionLink(entree.Name, "Details", new { id = entree.ID })
                </td>
                <td>
                    @Html.Partial("Ingredients", entree.Ingredients)
                </td>
            </tr>
        }
    </tbody>
</table>  

On the Details.cshtml view, we make a similar call:

@model PartialViewsDemo.Models.Entree

@{
    ViewBag.Title = "Details";
}

@Html.ActionLink("<< Back to Index", "Index")

<h2>@Model.Name</h2>

<p>Ingredients: @Html.Partial("Ingredients", Model.Ingredients)</p>  

With all of this in place, we can see our completed Index and Details pages.

The Entrees/Index page, showing all three Entrees and the partial call to Ingredients.cshtml

The Entrees/Details/2 page, showing the details for Entree 2 and the partial call to Ingredients.cshtml

An Alternate Rendering Method

In the previous examples we used a call to @Html.Partial() to render the partial views. There is also another call we can make, @Html.RenderPartial(), that will render the partial view in a different manner.

We would use it like this (here's a snippet from the Details view):

<p>Ingredients: @{ Html.RenderPartial("Ingredients", Model.Ingredients); }</p>  

Note that we had to use this call in server-side braces @{}. There's a couple of other differences between @Html.Partial() and @Html.RenderPartial():

  • @Html.Partial() returns a string (meaning you can store the output in a variable), whereas @Html.RenderPartial() returns void and writes directly to the Response.
  • Performance-wise @Html.RenderPartial() will perform better (per an answer on StackOverflow)

I almost always end up using [email protected]() just because I like the syntax better, but the decision is left to you.

Summary

Partial Views in ASP.NET MVC are meant to represent "pieces" of a page that can be rendered in multiple places on different views. They can have models bound to them, and can be rendered using @Html.Partial() or @Html.RenderPartial().

If you'd like to see this demo in a working MVC project, you can download the source from GitHub.

Happy Coding!