Section 4 of 6

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

Views/Shared/_Layout.cshtml HTML
<!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>&copy; @DateTime.Now.Year - InvenTrack</p>
    </footer>

    @await RenderSectionAsync("Scripts", required: false)
</body>
</html>
πŸ’‘ Key Methods

@RenderBody(): Renders the content of the child view
@RenderSection(): Renders optional/required sections

Using a Layout

Specify Layout in View

Views/Products/Index.cshtml HTML
@{
    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.

Views/_ViewStart.cshtml HTML
@{
    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

Views/Shared/_Layout.cshtml HTML
<head>
    <!-- Optional section -->
    @await RenderSectionAsync("Styles", required: false)
</head>
<body>
    @RenderBody()

    <!-- Required section -->
    @await RenderSectionAsync("Scripts", required: true)
</body>

Provide Section in View

Views/Products/Index.cshtml HTML
<h1>Products</h1>

@section Styles {
    <link rel="stylesheet" href="~/css/products.css">
}

@section Scripts {
    <script src="~/js/products.js"></script>
}

Check if Section Exists

Conditional Section Rendering HTML
@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

Views/Shared/_ProductCard.cshtml HTML
@model Product

<div class="card">
    <h3>@Model.Name</h3>
    <p>$@Model.Price</p>
    <p>Quantity: @Model.Quantity</p>
</div>

Render Partial View

Use Partial in View HTML
@model List<Product>

<div class="product-grid">
    @foreach (var product in Model)
    {
        <partial name="_ProductCard" model="product" />
    }
</div>

Alternative Syntax

Different Ways to Render Partials HTML
<!-- 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.

Views/_ViewImports.cshtml HTML
@using InvenTrack
@using InvenTrack.Models
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

Nested Layouts

You can create layouts that inherit from other layouts.

Views/Shared/_AdminLayout.cshtml HTML
@{
    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

Views/Shared/_Layout.cshtml HTML
<!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>&copy; @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>
Views/Shared/_ProductSummary.cshtml 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>
Views/Products/Index.cshtml HTML
@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
🎯 Next Steps

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.