ASP.NET Core 8 Website - Shared Razor Layout
PART 6: Creating a Shared Razor Layout
PART 5 moved Home and Privacy into Razor Pages, but each page still repeated the document structure, head section, stylesheet link and navigation markup. This part moves that common markup into one shared layout.
1. Stop the application
If the server is running, press Ctrl+C.
2. Create the shared directory
mkdir -p Pages/Shared
On Windows Command Prompt:
mkdir Pages\Shared
3. Create Pages/Shared/_Layout.cshtml
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, initial-scale=1.0">
<title>@ViewData["Title"] - basicdotnet</title>
<link rel="stylesheet" href="/css/site.css">
</head>
<body>
<header class="site-header">
<nav class="navigation">
<a class="site-name" href="/">
basicdotnet
</a>
<a class="nav-link" href="/">
Home
</a>
<a class="nav-link" href="/privacy">
Privacy
</a>
</nav>
</header>
@RenderBody()
</body>
</html>
4. Understand @RenderBody()
The layout contains the common page structure. The following expression marks the location where each page's unique content will be inserted:
@RenderBody()
When Home is requested, the contents of Index.cshtml are inserted there. When Privacy is requested, the contents of Privacy.cshtml are inserted instead.
5. Create Pages/_ViewStart.cshtml
@{
Layout = "_Layout";
}
_ViewStart.cshtml runs before each Razor Page. It tells all pages in the directory hierarchy to use the shared layout.
6. Simplify Pages/Index.cshtml
Replace the complete file with:
@page
@{
ViewData["Title"] = "Home";
string serverTime = DateTime.Now.ToString("HH:mm:ss");
}
<main class="page-content home-content">
<h1>Welcome to basicdotnet</h1>
<p>
A simple ASP.NET Core web app built
with Razor Pages.
</p>
<p>
It's @serverTime on the server.
</p>
</main>
7. Simplify Pages/Privacy.cshtml
@page
@{
ViewData["Title"] = "Privacy Policy";
}
<main class="page-content">
<h1>@ViewData["Title"]</h1>
<p>
basicdotnet is a demonstration application.
</p>
<p>
This website does not collect or store
personal information.
</p>
</main>
8. Create a Razor 404 page
Create Pages/NotFound.cshtml:
@page
@{
ViewData["Title"] = "Page Not Found";
Response.StatusCode = StatusCodes.Status404NotFound;
}
<main class="page-content">
<h1 class="error-code">
404 - Page Not Found
</h1>
<p>
The requested page could not be found.
</p>
<p>
<a href="/">Return to the Home page</a>
</p>
</main>
Setting Response.StatusCode ensures that the browser receives a genuine HTTP 404 response while still displaying the shared layout.
9. Simplify Program.cs
Replace its complete content with:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
var app = builder.Build();
app.UseStaticFiles();
app.UseRouting();
app.MapRazorPages();
app.MapFallbackToPage("/NotFound");
app.Run();
MapFallbackToPage("/NotFound") sends unmatched routes to the new Razor 404 page. The long fallback HTML string is no longer needed.
10. Check the project structure
basicdotnet/
├── Pages/
│ ├── Shared/
│ │ └── _Layout.cshtml
│ ├── _ViewStart.cshtml
│ ├── Index.cshtml
│ ├── NotFound.cshtml
│ └── Privacy.cshtml
├── wwwroot/
│ └── css/
│ └── site.css
├── basicdotnet.csproj
└── Program.cs
11. Build and run
dotnet build
dotnet run
12. Test all routes
| URL | Expected result |
|---|---|
/ | Home content inside the shared layout |
/privacy | Privacy content inside the shared layout |
/contact | Styled 404 content inside the shared layout |
How the layout works
Request for /privacy
↓
Privacy.cshtml provides unique content
↓
_ViewStart.cshtml selects _Layout
↓
_Layout.cshtml inserts the content at @RenderBody()
↓
The browser receives one complete HTML document
What has improved?
- The document structure exists in one file.
- The stylesheet is linked once.
- The navigation markup exists once.
- All pages receive a consistent appearance.
- Adding another page no longer requires copying the full HTML document.
Program.csnow contains only application configuration.
The website now uses the main structural idea behind the default Razor Pages template: individual pages provide content while a shared layout provides the surrounding interface.
Next: PART 7 introduces page-model files such as Index.cshtml.cs and moves the server-time logic out of the Razor markup.