blazor-routing-page-directive

@page Directive in Blazor: Routes and Parameters

  • 4 min

The @page directive associates a route template with a Razor component so the router can display it when visiting a URL.

Thus, when the user visits /products or /user/5, Blazor knows which component to render. The route is declared at the beginning of the .razor file.

Turning a Component into a Page

In Blazor, a page is a Razor component with an associated route.

The only difference is that a “Page” has an associated route that allows reaching it directly from the browser.

@page "/hello-world"

<h3>Hello from a URL!</h3>

@code { ... }
Copied!

By adding @page "/hello-world", the Blazor Router registers this component. If you navigate to https://yourdomain.com/hello-world, you will see this component rendered inside the MainLayout.

Important rule: The route must always start with a forward slash /. If you write @page "hello-world" (without the slash), you will get a compilation error.

Route Parameters

Static URLs are boring. Usually, we need to pass information through the address, like a product ID or category.

To define a variable parameter, we use curly braces {ParameterName} within the route string.

To capture that value in our C# code, we must create a public property with the [Parameter] attribute whose name matches (case-insensitive) the one in the route.

@page "/product/{ProductId}"

<h3>Product Detail: @ProductId</h3>

@code {
    [Parameter]
    public string ProductId { get; set; }
}
Copied!

Now, if you go to /product/1050, the ProductId variable will be “1050”.

Type Constraints and Conversion

To receive a value that is not a string, we specify a type constraint in the template. The router validates the segment and converts it to the corresponding CLR type.

@page "/order/{OrderId:int}"

<p>Viewing order number: @OrderId</p>

@code {
    [Parameter]
    public int OrderId { get; set; } // Automatic conversion from string to int
}
Copied!

What happens if the user types /order/three? Since “three” is not an integer, the route does not match and the application responds with the content not found page.

More Route Constraints

Sometimes we need to be stricter. If we have a route /user/{Id} where the ID must be a number, we don’t want the route to match if someone types /user/edit.

We can enforce the data type directly in the route definition using the colon :.

@page "/user/{Id:int}"

@page "/document/{Token:guid}"

@page "/filter/{IsActive:bool}"
Copied!

This is very useful for route overloading. You could have:

  • @page "/user/{Id:int}" -> To view a profile.
  • @page "/user/new" -> To create a new one (no conflict because “new” is not an int).

Optional Parameters

Sometimes a parameter is not mandatory. For example, a search route that may or may not have a term. Since .NET 5, we can mark a parameter as optional using a question mark ? at the end.

@page "/catalog/{Category?}"

<h3>
    @if (string.IsNullOrEmpty(Category))
    {
        <text>Showing entire catalog</text>
    }
    else
    {
        <text>Filtering by: @Category</text>
    }
</h3>

@code {
    [Parameter]
    public string? Category { get; set; }
}
Copied!

If you use optional parameters, make sure your C# property is nullable (e.g., string? or int?) to avoid null reference exceptions.

Multiple Routes for a Component

The same component can respond to several different URLs. Simply add multiple @page directives.

This is very useful for migrating old URLs or providing “simulated” default values.

@page "/profile"
@page "/profile/{UserId:int}"

<h3>Profile @(UserId.HasValue ? $"of {UserId}" : "Own")</h3>

@code {
    [Parameter]
    public int? UserId { get; set; }
}
Copied!
  1. If I go to /profile -> UserId is null.
  2. If I go to /profile/5 -> UserId is 5.

Catch-all Parameters

There are situations where we want to capture the rest of the URL, regardless of how many segments it has. This is typical in content management systems (CMS) or file managers.

The syntax {*variableName} is used.

@page "/files/{*Path}"

<p>You are browsing: @Path</p>

@code {
    [Parameter]
    public string? Path { get; set; }
}
Copied!
  • URL: /files/photos/vacations/2023.jpg
  • Value of Path: photos/vacations/2023.jpg

Query String Parameters

So far we have talked about routes (/product/5). But what about query parameters like /product?id=5&color=red?

The Router component does not use the query string to choose a route. To receive its values, we use [SupplyParameterFromQuery] on the corresponding properties.

@page "/search"

<p>Searching: @Term on page @Page</p>

@code {
    [SupplyParameterFromQuery(Name = "q")] // Maps ?q=...
    public string? Term { get; set; }

    [SupplyParameterFromQuery] // If you don't set Name, it uses the property name
    public int Page { get; set; }
}
Copied!

If we go to /search?q=blazor&page=2, the properties will be automatically populated.