Layouts and Partials
π― What You'll Learn
- Layout pages
- _ViewStart.cshtml
- _ViewImports.cshtml
- Partial views
- Sections
- Nested layouts
What are Layouts?
Layouts are master page templates that define the common structure (header, footer, navigation) for multiple pages.
Creating a Layout
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>@ViewData["Title"] - InvenTrack</title>
<link rel="stylesheet" href="~/css/site.css">
</head>
<body>
<header>
<nav>
<a asp-controller="Home" asp-action="Index">Home</a>
<a asp-controller="Products" asp-action="Index">Products</a>
</nav>
</header>
<main>
@RenderBody() <!-- Page content goes here -->
</main>
<footer>
<p>© @DateTime.Now.Year - InvenTrack</p>
</footer>
@await RenderSectionAsync("Scripts", required: false)
</body>
</html>
@RenderBody(): Renders the content of the child view
@RenderSection(): Renders optional/required sections
Using a Layout
Specify Layout in View
@{
Layout = "_Layout";
ViewData["Title"] = "Products";
}
<h1>Products</h1>
<p>This content will be rendered in @RenderBody()</p>
_ViewStart.cshtml
_ViewStart.cshtml sets the default layout for all views.
@{
Layout = "_Layout";
}
Now all views automatically use _Layout.cshtml.
Sections
Sections allow views to inject content into specific areas of the layout.
Define Section in Layout
<head>
<!-- Optional section -->
@await RenderSectionAsync("Styles", required: false)
</head>
<body>
@RenderBody()
<!-- Required section -->
@await RenderSectionAsync("Scripts", required: true)
</body>
Provide Section in View
<h1>Products</h1>
@section Styles {
<link rel="stylesheet" href="~/css/products.css">
}
@section Scripts {
<script src="~/js/products.js"></script>
}
Check if Section Exists
@if (IsSectionDefined("Styles"))
{
@await RenderSectionAsync("Styles")
}
@else
{
<link rel="stylesheet" href="~/css/default.css">
}
Partial Views
Partial views are reusable UI components that can be included in multiple views.
Create Partial View
@model Product
<div class="card">
<h3>@Model.Name</h3>
<p>$@Model.Price</p>
<p>Quantity: @Model.Quantity</p>
</div>
Render Partial View
@model List<Product>
<div class="product-grid">
@foreach (var product in Model)
{
<partial name="_ProductCard" model="product" />
}
</div>
Alternative Syntax
<!-- Tag Helper (recommended) -->
<partial name="_ProductCard" model="product" />
<!-- HTML Helper -->
@await Html.PartialAsync("_ProductCard", product)
<!-- Synchronous (avoid) -->
@Html.Partial("_ProductCard", product)
_ViewImports.cshtml
_ViewImports.cshtml imports namespaces and tag helpers for all views.
@using InvenTrack
@using InvenTrack.Models
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
Nested Layouts
You can create layouts that inherit from other layouts.
@{
Layout = "_Layout"; // Inherit from main layout
}
<div class="admin-sidebar">
<a asp-controller="Admin" asp-action="Dashboard">Dashboard</a>
<a asp-controller="Admin" asp-action="Users">Users</a>
</div>
<div class="admin-content">
@RenderBody()
</div>
Complete InvenTrack Example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>@ViewData["Title"] - InvenTrack</title>
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="~/css/site.css">
@await RenderSectionAsync("Styles", required: false)
</head>
<body>
<header>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container">
<a class="navbar-brand" asp-controller="Home" asp-action="Index">InvenTrack</a>
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" asp-controller="Products" asp-action="Index">Products</a>
</li>
<li class="nav-item">
<a class="nav-link" asp-controller="Orders" asp-action="Index">Orders</a>
</li>
</ul>
</div>
</nav>
</header>
<main class="container mt-4">
@RenderBody()
</main>
<footer class="footer mt-5 py-3 bg-light">
<div class="container text-center">
<p>© @DateTime.Now.Year - InvenTrack. All rights reserved.</p>
</div>
</footer>
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
@await RenderSectionAsync("Scripts", required: false)
</body>
</html>
@model Product
<div class="card mb-3">
<div class="card-body">
<h5 class="card-title">@Model.Name</h5>
<p class="card-text">@Model.Category</p>
<p class="card-text">
<strong>$@Model.Price.ToString("F2")</strong>
</p>
<a asp-action="Details" asp-route-id="@Model.Id" class="btn btn-primary">View Details</a>
</div>
</div>
@model List<Product>
@{
ViewData["Title"] = "Products";
}
<h1>Products</h1>
<div class="row">
@foreach (var product in Model)
{
<div class="col-md-4">
<partial name="_ProductSummary" model="product" />
</div>
}
</div>
@section Scripts {
<script>
console.log('Loaded @Model.Count products');
</script>
}
Best Practices
- Use _ViewStart: Set default layout for all views
- Use _ViewImports: Import common namespaces
- Partial naming: Prefix partials with underscore (_ProductCard)
- Async rendering: Use @await for partials and sections
- Optional sections: Set required: false for optional sections
- Reusable partials: Create partials for repeated UI components
Key Takeaways
- Layouts: Master page templates
- @RenderBody(): Renders child view content
- @RenderSection(): Renders optional/required sections
- _ViewStart.cshtml: Sets default layout
- _ViewImports.cshtml: Imports namespaces and tag helpers
- Partial views: Reusable UI components
- <partial>: Tag helper for rendering partials
- Nested layouts: Layouts can inherit from other layouts
You now understand layouts and partials! In the next section, we'll explore View Componentsβmore powerful, reusable components with their own logic and data access.