Razor Pages and Razor Components — Rendering HTML
ReadingRoom's API serves apps, but the librarians want web pages: a list of overdue loans, a search box. ASP.NET Core offers two HTML models built on the same Razor syntax — C# mixed into HTML with @. Knowing which fits saves you from forcing one into the other's job.
The rule
A page answers a request; a component is a reusable, possibly live, piece.
A Razor Page is one URL: a .cshtml file starting with @page, plus a PageModel class whose handlers run per request.
@page
@model OverdueModel
<h1>Overdue loans</h1>
<ul>
@foreach (var loan in Model.Loans)
{
<li>@loan.BookTitle, due @loan.DueDate.ToShortDateString()</li>
}
</ul>public class OverdueModel(LibraryDb db) : PageModel
{
public List<LoanRow> Loans { get; private set; } = [];
public void OnGet() => Loans = db.OverdueLoans();
}The file Pages/Overdue.cshtml is served at /Overdue. OnGet handles GET, OnPost handles a form post. Switch it on with AddRazorPages() and MapRazorPages().
A Razor Component is a .razor file: markup plus an @code block. Components nest inside each other and take [Parameter] inputs. This is Blazor.
@rendermode InteractiveServer
<input @bind="term" @bind:event="oninput" />
<p>@Matches().Count() books match</p>
@code {
[Parameter] public List<Book> Books { get; set; } = [];
string term = "";
IEnumerable<Book> Matches() => Books.Where(b => b.Title.Contains(term));
}Since .NET 8, a component's render mode, set on it or inherited from a parent, decides how it behaves. With no interactive mode, it renders once on the server as static HTML. InteractiveServer keeps a live connection so clicks and typing run your C# on the server; InteractiveWebAssembly runs it in the browser; InteractiveAuto starts on the server and switches later.
The shortcut
Ask: does anything on screen change without a new request? No → a Razor Page (or a static component). Yes → an interactive Razor Component.
The overdue list
It is fetched once when the page opens. Nothing changes until the next visit.
The trap: building the search box as a component but leaving it without any interactive render mode. It renders fine, then silently ignores typing.
Drills
Answer fast — trust the rule.
Which directive makes a .cshtml file a Razor Page with its own URL?
A Razor Page needs to handle a submitted form. Which handler runs?
A component gets no interactive render mode, its own or inherited. What happens when a user clicks its @onclick button?
Where does an InteractiveWebAssembly component run its C#?
Remember
- A page answers a request; a component is a reusable, possibly live, piece.
- Razor Pages:
@pageplusOnGet/OnPost. Components:.razorplus@code. - Anything changing without a new request needs an interactive render mode.
