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:
Now that we've got our partial view defined, we can define the EntreeController
and the Index()
and Details()
actions, along with their corresponding views. First, here's the EntreeController
:
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.
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 theResponse
.- Performance-wise
@Html.RenderPartial()
will perform better (per an answer on StackOverflow)
I almost always end up using @Html.Partial()
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 check out the sample project over on GitHub.
Happy Coding!