Blazor Server Routing

On a single-page website, you change what the user sees by showing or hiding portions of the display that correspond to particular components, rather than going out to the server to get a new page. As users perform application tasks, they need to move between the different Razor Components that you have defined.

Download the example for a working example containing the code snippets in this guide.

Prerequisites

Before creating a route, you should be familiar with the following:


Setting up basic routing

Blazor Server was built on top of ASP.NET and Razor Pages. When you create a Blazor Server website, there will be a pre-configuration code at Startup.cs. These are some routing pre-configuration codes for routing.

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
    }

    app.UseStaticFiles();

    app.UseRouting();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapBlazorHub();
        endpoints.MapFallbackToPage("/_Host");
    });
}

We will go through line by line to analyze what is pre-configured. Starting at the first block:

if (env.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}
else
{
    app.UseExceptionHandler("/Error");
}

This if statement will determine if we are in development environment or production environment and use the respective error page. You can find the error page at Pages/Error.cshtml. the UseDeveloperExceptionPage method is a built-in middleware to capture unhandled exceptions in detail. Detailed exception information should not be displayed publicly in the production environment for security reasons.

app.UseRouting();

app.UseEndpoints(endpoints =>
{
    endpoints.MapBlazorHub();
    endpoints.MapFallbackToPage("/_Host");
});

The UseRouting method to indicate that we will use default routing of ASP.NET. UseRouting must be used with UseEndpoints and are required by ASP.NET.

The MapBlazorHub method is to open the default port for SignalR Core to interact with the frontend of Blazor Server.

The MapFallbackToPage method to indicate the entry point of Blazor Server. The default entry point is located in Pages/_Host.cshtml, you can change this entry point to another Razor Page. Whenever a requested url does not match any @page directive, Blazor Server will redirect to the default entry point.

You can only use Razor Page as the entry point of Blazor Server website.

Defining a route

You can use @page directive in a Razor Component to define a route to a component.

  • The @page directive always begins with a forward splash (/).
  • A Razor Component can have many @page directives to have many routes.
  • If the requested url matches many routes, Blazor Server prioritizes the most nested route first.
  • A route must be unique to the entire website.
  • A route can have parameter(s).

To define a route for a component, add a @page directive to the directive section of the component.

@page "/simple-route" 

<h3>This is a simple page</h3>

In the example, we set the route host/simple-route for the component. When the user navigates to that route, the component will be rendered.

Blazor Server routing

Route selection

Blazor Server uses more-specific wins strategy when matching routes. For example: consider you have 2 components, User component with "/user" and UserDetail component with "/user/{id:int}", if the requested url is "/user/1" then the UserDetail component will be selected because the UserDetail component has more nested routes than the User component.
The route "/" is the index route. By default, it is used in Index.razor component but you can move it to another component.
If no route matches, Blazor Server will use the route in MapFallbackToPage to select the Razor Page.

Getting route information

Often, as a user navigates your website, you want to pass information from one component to another. For example, consider a website that displays a list of books. Each book on the list has a unique id. To edit a book, users click the Edit button, which opens a EditBook component. You want that component to retrieve the id for the book so it can display the right information to the user.

You can use a route to pass this type of information to your website components. To do so, you use the [Parameter] attribute.

To get information from a route:

  1. Determine the type of information from the route. Here is the list of data types from route.
Type in route Example data Type in C#
bool true, FALSE bool
datetime 2021-12-31, 2021-12-31 8:40pm DateTime
decimal 99.99, -1,00 decimal
float 1.234, -1,001.01e8 float
guid CD2C1638-1638-72D5-1638-DEADBEEF1638, {CD2C1638-1638-72D5-1638-DEADBEEF1638} Guid
int 123456789, -123456789 int, Int32
long 123456789, -123456789 long, Int64
short 123456789, -123456789 short, Int16
double 1.234, -1,001.01e8 double, Double
BlazorSchool, blazorschool.com string, String
  1. Declare a public property in the @code{} section with the matching type in C#. Example:
@page "/route-parameters/{number:double}"

<h3>Number: @Number</h3>

@code{
    [Parameter]
    public double Number { get; set; }
}

Optional parameters

A route can have multiple parameters with optional parameters, for optional parameters, add question mark (?) after the route type.

@page "/route-parameters/{number:double}/{firstName?}/{isGraduate:bool?}"

The {firstName?} is to indicate that there will be an optional string FirstName property. String is a special type in route parameter that does not have a route type. The {isGraduate:bool?} is to indicate that there will be an optional bool IsGraduate property.

When there is more than one optional parameter, the former must be provided before the latter. In the previous example, you could not fill IsGraduate without filling FirstName first.

The optional parameters must be the last parameter specified in the route.

Cultured parameters

There are several types of numbers, in some cultures, the decimal symbol are different. A common problem is the dot (.) symbol could be a decimal symbol, a file extension symbol or it can appears on string parameter. Blazor Server cannot distinguish between these. By default, Blazor Server will assume the dot symbol is a request for a file and will emit a 404 error. You have to tell Blazor Server that for this specific case, the dot is a part of parameter by going to Startup.cs and modifying the Configure method as follows.

app.UseEndpoints(endpoints =>
{
    ...
    endpoints.MapFallbackToPage("/route-parameters/{number:double}/{firstName?}/{isGraduate:bool?}","/_Host");
    ...
});

Customizing a 404 page

Blazor Server has a pre-built 404 page, and you can customize it. You can see the pre-built 404 page at App.razor.

<NotFound>
    <LayoutView Layout="@typeof(MainLayout)">
        <p>Sorry, there's nothing at this address.</p>
    </LayoutView>
</NotFound>

Create a new component in Pages folder called NotFound.razor.

<h1>404 page not found.</h1>

Update the App.razor to use the NotFound component.

@using RoutingExample.Pages

...
<NotFound>
    <LayoutView Layout="@typeof(MainLayout)">
        <NotFound></NotFound>
    </LayoutView>
</NotFound>
...

Control navigation with UI elements

Adding links that users can click to navigate between pages is a crucial part of any website. There are 2 ways to create a link in Blazor Server. You can either use <a> tag or use <NavLink> pre-built component.

Using <NavLink> component

<NavLink>, as the name suggested, is usually used in the navigation bar. <NavLink> is a pre-built component that automatically toggling its 'active' class based on whether its href matches the current URL. Refer to Navigation.razor in our example.

@page "/navigation" 

<NavLink class="page-link" href="navigation">Link 1</NavLink>

This is a basic nav link example, it will render the following HTML.

<a href="navigation" class="page-link active">Link 1</a>

Declare a css style to toggling the <NavLink> in site.css.

.active-link
{
    color: white;
    background-color: #7b3cc3
}
You cannot use isolated CSS for this .active-link class because the rendered HTML has no scope attribute.

Add a parameter ActiveClass to use the class with the <NavLink> component.

<NavLink class="page-link" href="navigation" ActiveClass="active-link">Link 1</NavLink>

The following HTML is rendered.

<a href="navigation" class="page-link active-link">Link 1</a>

The link has now been highlighted because the current URL matches to the href in <NavLink>. Also, the active class in the first rendered HTML has been changed to active-link.

In some cases, you have a nested route like "host/navigation/link-2" and you want to highlight only the link of this particular route. This is where Matches parameter comes in. Add another link to the example.

@page "/navigation"
@page "/navigation/link-2"

<NavLink class="page-link" href="navigation" ActiveClass="active-link">Link 1</NavLink>
<NavLink class="page-link" href="navigation/link-2" ActiveClass="active-link">Link 2</NavLink>

When you navigate to "/navigation/link-2", you will see that 2 links are activated.

To activate only Link 2, you need to add Match parameter to both <NavLink> components. NavLinkMatch.All is to indicate that the only link to the extractive URL will be highlighted.

<NavLink class="page-link" href="navigation" ActiveClass="active-link" Match="NavLinkMatch.All">Link 1</NavLink>
<NavLink class="page-link" href="navigation/link-2" ActiveClass="active-link" Match="NavLinkMatch.All">Link 2</NavLink>

Navigate to "/navigation/link-2" and you will only see Link 2 activated.

Link 1 and Link 2 are siblings so highlighting both Link 1 and Link 2 is something you don't want to. But in some cases, you have parent and child links and you want to highlight the parent whenever a child is selected. Add Link 3, Link 3.1 and Link 3.2 to the example.

...
@page "/navigation/link-3"
@page "/navigation/link-3/child-1"
@page "/navigation/link-3/child-2"

...
<NavLink class="page-link" href="navigation/link-3" ActiveClass="active-link" Match="NavLinkMatch.Prefix">Link 3</NavLink>
<NavLink class="page-link" href="navigation/link-3/child-1" ActiveClass="active-link" Match="NavLinkMatch.All">Link 3.1</NavLink>
<NavLink class="page-link" href="navigation/link-3/child-2" ActiveClass="active-link" Match="NavLinkMatch.All">Link 3.2</NavLink>

Use the NavLinkMatch.Prefix for the parent link and use NavLinkMatch.All for the children. By using NavLinkMatch.Prefix on the parent link you are telling <NavLink> to highlight every URL that starts with "/navigation/link-3", that's including the "/navigation/link-3/child-1" and "/navigation/link-3/child-2".


Control navigation by NavigationManager

NavigationManager is a good way to navigate to a page without user interaction with the UI. For example, if you want to redirect a user to a page in 5 seconds you will need to use NavigationManager because the user will not interact with the UI.

To use NavigationManager, you need to inject it first. If you are in Razor Component, you can inject NavigationManager like this:

@inject NavigationManager NavigationManager

Or if you are in a service class, you can inject it as follows:

public class <Class Name>
{
    private readonly NavigationManager _navigationManager;

    public <Class Name>(NavigationManager navigationManager)
    {
        _navigationManager = navigationManager;
    }
}

NavigationManager can redirect users to other pages inside the website or even outside the website.

In case of inside redirection, pass a related url to the first parameter, the second parameter indicates Blazor Server should make a reload in between. By default, Blazor Server does not reload page on navigating.

NavigationManager.NavigateTo("/", false);

In case of external redirection, pass an absolute url to the first parameter, the second parameter is useless in this case because you are leaving Blazor Server.

NavigationManager.NavigateTo("https://blazorschool.com", false);
BLAZOR SCHOOL
Designed and built with care by our dedicated team, with contributions from a supportive community. We strive to provide the best learning experience for our users.
Docs licensed CC-BY-SA-4.0
Copyright © 2021-2025 Blazor School
An unhandled error has occurred. Reload 🗙