Tutorials ASP.NET Core MVC Mastery
Layouts & Sections
On this page
Layouts & Sections in ASP.NET Core MVC β Architecting the UI Foundation
Every page on your application shares a common DNA β the header, navigation, footer, and meta tags. Without layouts, you'd be copy-pasting this code across hundreds of views. Layouts in ASP.NET Core MVC let you define this structure once and inject unique content into it from any view, creating a clean, maintainable UI architecture.
1. WHAT Are Layouts?
A Layout is a Razor template (.cshtml) that defines the common HTML skeleton shared by multiple views β the <html>, <head>, <body> tags, navigation bars, footers, and shared CSS/JS references. Individual views then inject their unique content into this skeleton via @RenderBody().
The Architecture
ββββββββββββββββββββββββββββββββββββββββ
β _Layout.cshtml β
β ββββββββββββββββββββββββββββββββββ β
β β <nav> Navigation Bar </nav> β β
β ββββββββββββββββββββββββββββββββββ€ β
β β β β
β β @RenderBody() β β
β β (Your View Content Here) β β
β β β β
β ββββββββββββββββββββββββββββββββββ€ β
β β <footer> Footer </footer> β β
β ββββββββββββββββββββββββββββββββββ€ β
β β @RenderSection("Scripts") β β
β ββββββββββββββββββββββββββββββββββ β
ββββββββββββββββββββββββββββββββββββββββ
2. The Three Pillars: RenderBody, RenderSection, _ViewStart
@RenderBody()
The mandatory placeholder where child view content is injected. Only ONE per layout. Think of it as the "main content area."
@RenderSection()
Named slots that child views can optionally fill. Perfect for page-specific CSS, JavaScript, or sidebar content. Use required: false for optional sections.
_ViewStart.cshtml
Executes before every view in its directory (and subdirectories). Used to set the default layout globally so you don't repeat Layout = "_Layout" in every view.
3. REAL-TIME PRODUCTION EXAMPLES
Example 1: Production-Ready Layout with Multiple Sections
<!-- Views/Shared/_Layout.cshtml -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="@ViewData["MetaDescription"]" />
<title>@ViewData["Title"] β MyApp</title>
<!-- Global CSS -->
<link rel="stylesheet" href="~/css/app.min.css" />
<!-- Page-specific CSS (optional) -->
@RenderSection("Styles", required: false)
</head>
<body>
<!-- Shared Navigation -->
<partial name="_Navbar" />
<!-- Flash Messages -->
<partial name="_Notifications" />
<!-- MAIN CONTENT β Each view's content renders here -->
<main class="container py-4">
@RenderBody()
</main>
<!-- Shared Footer -->
<partial name="_Footer" />
<!-- Global JS (loaded last for performance) -->
<script src="~/js/app.min.js"></script>
<!-- Page-specific JS (optional) -->
@RenderSection("Scripts", required: false)
</body>
</html>
Example 2: Child View Using the Layout
<!-- Views/Products/Index.cshtml -->
@model IEnumerable<Product>
@{
ViewData["Title"] = "All Products";
ViewData["MetaDescription"] = "Browse our complete product catalog";
}
<h1>Product Catalog</h1>
<div class="row">
@foreach (var product in Model)
{
<div class="col-md-4">
<partial name="_ProductCard" model="product" />
</div>
}
</div>
@section Styles {
<link rel="stylesheet" href="~/css/products.css" />
}
@section Scripts {
<script src="~/js/product-filter.js"></script>
<script>
ProductFilter.init({ container: '.row' });
</script>
}
Example 3: Nested Layouts (Admin vs Public)
<!-- Views/Shared/_AdminLayout.cshtml β Extends _Layout.cshtml -->
@{
Layout = "_Layout"; // This layout WRAPS itself inside the main layout
ViewData["Title"] = "Admin: " + ViewData["Title"];
}
<div class="d-flex">
<!-- Admin Sidebar -->
<nav class="admin-sidebar bg-dark text-white" style="width:280px; min-height:100vh;">
<div class="p-3">
<h5>β‘ Admin Panel</h5>
<a href="/admin/dashboard" class="nav-link text-white">Dashboard</a>
<a href="/admin/users" class="nav-link text-white">Users</a>
<a href="/admin/products" class="nav-link text-white">Products</a>
<a href="/admin/orders" class="nav-link text-white">Orders</a>
</div>
</nav>
<!-- Admin Content Area -->
<main class="flex-grow-1 p-4">
@RenderBody()
</main>
</div>
<!-- Views/Admin/Dashboard.cshtml β Uses the nested admin layout -->
@{
Layout = "_AdminLayout"; // Uses the admin layout (which wraps inside _Layout)
ViewData["Title"] = "Dashboard";
}
<h2>Welcome to the Admin Dashboard</h2>
<!-- This content renders inside _AdminLayout β inside _Layout -->
Example 4: _ViewStart.cshtml β The Global Default
<!-- Views/_ViewStart.cshtml -->
@{
Layout = "_Layout"; // ALL views in /Views/ use this layout by default
}
<!-- You can also create folder-specific _ViewStart files: -->
<!-- Views/Admin/_ViewStart.cshtml -->
@{
Layout = "_AdminLayout"; // ALL views in /Views/Admin/ use the admin layout
}
4. Sections: Required vs Optional
// In the Layout:
@RenderSection("Scripts", required: false) // Optional: won't crash if not defined
@RenderSection("Sidebar", required: true) // Required: crash if view doesn't define it
// Conditional rendering with IsSectionDefined:
@if (IsSectionDefined("Sidebar"))
{
<aside class="sidebar">
@RenderSection("Sidebar")
</aside>
}
else
{
<aside class="sidebar">
<partial name="_DefaultSidebar" />
</aside>
}
5. Layout vs Partial View vs View Component
| Feature | Layout | Partial View | View Component |
|---|---|---|---|
| Purpose | Page-level HTML skeleton | Reusable UI fragment | Self-contained UI + Logic |
| Has its own controller? | β No | β No | β Yes (InvokeAsync) |
| Can access DI? | Via @inject | Via @inject | β Full DI in class |
| Best For | Headers, footers, nav | Product cards, forms | Shopping cart, recent posts |
| Data Source | ViewData/Model | Model passed from parent | Own data from DB/service |
6. Best Practices
β DO
- Use
_ViewStart.cshtmlfor default layout assignment - Create folder-specific
_ViewStartfiles for different areas (Admin, Public) - Use
required: falsefor optional sections like Scripts and Styles - Use
IsSectionDefined()to provide default content when sections aren't filled - Use nested layouts for Admin/Public separation
β DON'T
- Don't put business logic in layouts β they're for structure only
- Don't use more than one
@RenderBody()in a layout - Don't forget to define required sections β it causes runtime errors
- Don't use partial views for complex components that need their own data β use View Components
- Don't inline large CSS/JS in sections β reference external files
7. Interview Mastery
Q: "How do you structure layouts in a large enterprise application with multiple user roles?"
Architect Answer: "I use nested layouts with folder-specific _ViewStart.cshtml files. The root _Layout.cshtml handles the outermost HTML, meta tags, and shared CSS/JS bundles. Then I create role-specific layouts β _AdminLayout, _CustomerLayout, _VendorLayout β each defining their own sidebar, navigation, and permission-aware menus. Each of these sets Layout = '_Layout' to inherit the global structure. This creates a clean hierarchy: Global β Role-Specific β View, keeping hundreds of views DRY while allowing each section to have its own visual identity."