Shared Layout

Provide a consistent site shell (nav + header + footer) used by all pages via _ViewStart.cshtml.

Full source

File: pwsh/tutorial/examples/11.1-RazorPages.ps1

<#
    Sample Kestrun Server showing PowerShell-backed Razor Pages.
    This example demonstrates enabling the Razor Pages runtime and serving pages from a root folder.
    FileName: 11.1-RazorPages.ps1
#>

param(
    [int]$Port = 5000,
    [IPAddress]$IPAddress = [IPAddress]::Loopback
)

# Initialize Kestrun root directory
# the default value is $PWD
# This is recommended in order to use relative paths without issues
Initialize-KrRoot -Path $PSScriptRoot

# Create a new logger
New-KrLogger |
    Set-KrLoggerLevel -Value Debug |
    Add-KrSinkConsole |
    Register-KrLogger -SetAsDefault -Name 'DefaultLogger'

# Create a new Kestrun server
New-KrServer -Name 'RazorPages'

# Add a listener on the configured port and IP address
Add-KrEndpoint -Port $Port -IPAddress $IPAddress

# Add a Razor Pages handler to the server
Add-KrPowerShellRazorPagesRuntime -RootPath './Assets/Pages'

# Application-wide metadata (AVAILABLE TO ALL RUNSPACES)
$AppInfo = [pscustomobject]@{
    Name = 'Kestrun Razor Demo'
    Environment = 'Development'
    StartedUtc = [DateTime]::UtcNow
    Version = Get-KrVersion -AsString
}

Write-KrLog -Level Information -Message "Starting Kestrun RazorPages server '{name}' version {version} in {environment} environment on {ipaddress}:{port}" `
    -Values $AppInfo.Name, $AppInfo.Version, $AppInfo.Environment, $IPAddress, $Port

# Define feature flags for the application
$FeatureFlags = @{
    RazorPages = $true
    Cancellation = $true
    HotReload = $false
}

Write-KrLog -Level Information -Message 'Feature Flags: {featureflags}' -Values $($FeatureFlags | ConvertTo-Json -Depth 3)

# Define a Message of the Day (MOTD) accessible to all pages
$Motd = @'
Welcome to Kestrun.
This message comes from the main server script.
Defined once, visible everywhere.
'@

Write-KrLog -Level Information -Message 'Message of the Day: {motd}' -Values $Motd

# Enable Kestrun configuration
Enable-KrConfiguration


# Start the server asynchronously
Start-KrServer

File: pwsh/tutorial/examples/Assets/Pages/Shared/_Layout.cshtml

@{
    // IMPORTANT:
    // Do NOT set Layout here (layouts must not have layouts)
    // Do NOT assume a model exists
    var title = ViewData["Title"] as string ?? "Kestrun • Razor + PowerShell";
}

<!doctype html>
<html lang="en">

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>@title</title>

    <style>
        body {
            margin: 0;
            font-family: system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif;
            background: #0b1020;
            color: #e7eaf3;
        }

        header {
            background: rgba(255, 255, 255, 0.06);
            border-bottom: 1px solid rgba(255, 255, 255, 0.08);
            padding: 1rem 1.25rem;
        }

        main {
            max-width: 1000px;
            margin: 0 auto;
            padding: 1.5rem;
        }

        nav a {
            margin-right: 1rem;
            color: #9ad1ff;
            text-decoration: none;
        }

        nav a:hover {
            text-decoration: underline;
        }

        footer {
            margin-top: 3rem;
            padding-top: 1rem;
            border-top: 1px solid rgba(255, 255, 255, 0.08);
            color: rgba(231, 234, 243, 0.7);
            font-size: 0.9rem;
        }

        .card {
            background: rgba(255, 255, 255, 0.06);
            border: 1px solid rgba(255, 255, 255, 0.08);
            border-radius: 10px;
            padding: 1rem;
            margin-bottom: 1rem;
        }

        code,
        pre {
            background: rgba(0, 0, 0, 0.35);
            padding: 0.25rem 0.4rem;
            border-radius: 6px;
        }

        pre {
            padding: 0.8rem;
            overflow-x: auto;
        }
    </style>
</head>

<body>
    <header>
        <div style="max-width:1000px; margin:0 auto; display:flex; justify-content:space-between; align-items:center;">
            <div>
                <strong>Kestrun</strong><br />
                <span style="font-size:0.85rem; opacity:0.8;">
                    Razor Pages + PowerShell
                </span>
            </div>

            <nav>
                <a href="@Context.Request.PathBase/">Home</a>
                <a href="@Context.Request.PathBase/About">About</a>
                <a href="@Context.Request.PathBase/Status">Status</a>
                <a href="@Context.Request.PathBase/Quotes">Quotes</a>
                <a href="@Context.Request.PathBase/Contact">Contact</a>
                <a href="@Context.Request.PathBase/AppInfo">App Info</a>
                <a href="@Context.Request.PathBase/Cancel">Cancel</a>
            </nav>
        </div>
    </header>

    <main>
        @RenderBody()

        <footer>
            Served at @DateTime.UtcNow.ToString("u")
        </footer>
    </main>
</body>

</html>

Step-by-step

  1. Title: Read ViewData["Title"] and fall back to a default.
  2. Styling: Define minimal CSS for the demo.
  3. Navigation: Render links to each sample page.
  4. Body: Render the current page with @RenderBody().
  5. Footer: Display a simple UTC timestamp.

Try it

Any page uses this layout (unless it sets Layout = null):

curl -i http://127.0.0.1:5000/

Troubleshooting

Symptom Cause Fix
Layout not applied _ViewStart.cshtml not setting Layout Ensure Assets/Pages/_ViewStart.cshtml sets Layout = "Shared/_Layout"
Links don’t work when hosted under a path base Hard-coded absolute URLs This layout uses @Context.Request.PathBase to prefix links

References


Previous / Next

Previous: Cancel Next: ViewStart