Routing with @page
Blazor uses the @page directive at the top of a .razor file to register a component as a routable endpoint. At startup, the Router component scans the assemblies you configure and builds a route table by reading every @page attribute, similar to how ASP.NET Core MVC discovers controller actions via attribute routing. When a user navigates to a matching URL, either via a browser address bar request or an in-app NavLink click, the router instantiates that component and renders it inside the layout.
Cricket analogy: Just as an umpire's decision review system checks a predefined set of camera angles before ruling on an LBW, Blazor's Router scans configured assemblies at startup and builds a lookup table of every @page attribute before any URL is matched.
Route Templates and Parameters
A route template like @page "/students/{id}" declares a segment that is captured as a component parameter; the corresponding C# property must be marked [Parameter] and named exactly Id (case-insensitive) with a matching type via a route constraint, e.g. {id:int}. You can stack multiple @page directives on a single component to expose it at several URLs, such as both "/students" and "/students/{id:int}", letting one component handle a list view and a detail view.
Cricket analogy: Like naming a specific fielding position such as gully so everyone knows exactly which player covers it, the {id:int} constraint tells Blazor exactly which C# property, Id, should catch that URL segment.
Parameters can be made optional by appending a question mark to the constraint, as in {id:int?}, which requires the bound property to be a nullable type like int?. Omitting the segment entirely then renders the component with that parameter left null, so your code must branch on whether a value was supplied instead of assuming a valid id is always present.
Cricket analogy: Like a Duckworth-Lewis calculation that only kicks in when rain interrupts a match, an optional {id:int?} route only supplies a value when the URL segment is actually present, otherwise the property stays null.
Route Constraints
Blazor route constraints restrict which values a segment accepts before the router even instantiates the component: {id:int}, {id:bool}, {id:datetime}, {id:decimal}, {id:double}, {id:float}, {id:guid}, {id:long}, and {id:non-file-name} are the built-in options. If the actual URL segment can't be parsed as that type, the router treats the route as not matching, so a request for /students/abc against {id:int} falls through to another route or to NotFound content instead of throwing at runtime.
Cricket analogy: Like a run-out review that only proceeds if the throw actually reaches the stumps in a way the technology can measure, Blazor's {id:int} constraint only matches if the segment can actually be parsed as an integer, otherwise the route is skipped.
@page "/students"
@page "/students/{id:int}"
<h3>Student Directory</h3>
@if (Id is null)
{
<ul>
@foreach (var s in students)
{
<li><a href="/students/@s.Id">@s.Name</a></li>
}
</ul>
}
else
{
<p>Showing details for student #@Id</p>
}
@code {
[Parameter]
public int? Id { get; set; }
private List<Student> students = new();
protected override void OnInitialized()
{
students = StudentRepository.GetAll();
}
}The Router component in App.razor only discovers @page routes from assemblies it's told to scan. If your routable components live in a separate class library (a shared Razor Class Library), you must add it to the Router's AdditionalAssemblies parameter, e.g. <Router AppAssembly="@typeof(Program).Assembly" AdditionalAssemblies="new[] { typeof(SharedComponent).Assembly }">, or those @page routes will never appear in the route table.
Catch-all Route Parameters
A catch-all parameter, written as {*path}, captures the remainder of the URL including slashes into a single string property, which is useful for components like a documentation viewer or file browser that need an arbitrary nested path such as /docs/guides/advanced/routing. Because the captured segments aren't URL-decoded per segment the way individual route parameters are, catch-all values are decoded as a whole and won't cleanly split back into constrained sub-segments.
Cricket analogy: Like a fielding captain assigning one player to cover the entire deep boundary rather than a single fixed spot, a catch-all {*path} parameter captures an entire remaining URL path, slashes and all, into one string.
Two components declaring overlapping @page templates, such as "/items/{id}" on one component and "/items/{name}" on another, produces an AmbiguousMatchException at runtime because Blazor cannot deterministically decide which one should win. Route matching order is not guaranteed to follow declaration order, so always design distinct, non-overlapping templates rather than relying on which file happens to load first.
- The @page directive registers a component as a routable endpoint, and the Router builds its full route table from these attributes at startup.
- Route parameters are captured into [Parameter] properties whose name matches the segment name and whose type matches the route constraint.
- A component can carry multiple @page directives to serve several related URLs, such as a list view and a detail view.
- Appending ? to a constraint, like {id:int?}, makes the segment optional and requires a nullable bound property.
- Built-in constraints (int, bool, datetime, decimal, double, float, guid, long, non-file-name) reject non-matching segments before the component is instantiated.
- Catch-all parameters ({*path}) capture an entire remaining nested URL, including slashes, into one string property.
- Overlapping route templates across components cause an AmbiguousMatchException, so keep templates distinct.
Practice what you learned
1. What C# attribute must a property carry to receive a value from a route segment?
2. Which route template correctly makes the id segment optional?
3. What happens when a URL segment fails to satisfy a route constraint like {id:int}?
4. What does a catch-all route parameter such as {*path} capture?
5. Why must the Router's AdditionalAssemblies parameter be configured for some @page components to work?
Was this page helpful?
You May Also Like
Navigation and NavigationManager
Understand how Blazor's NavigationManager service enables programmatic navigation, URL inspection, and location-change event handling.
Authentication and AuthorizeView
Learn how Blazor's AuthenticationStateProvider, AuthorizeView, and the [Authorize] attribute work together to build authentication-aware UI.
Related Reading
Related Study Notes in Microsoft Technologies
Browse all study notesWindows 10 / UWP Development Study Notes
.NET · 30 topics
Microsoft TechnologiesWindows Batch Scripting Study Notes
Batch · 30 topics
Microsoft TechnologiesMFC (Microsoft Foundation Classes) Study Notes
C++ · 30 topics
Microsoft TechnologiesSilverlight Study Notes
.NET · 30 topics
Microsoft TechnologiesXAML Study Notes
.NET · 30 topics
Microsoft TechnologiesWPF (Windows Presentation Foundation) Study Notes
.NET · 30 topics