Routing And Navigation In Blazor

Routing in a Blazor application is the system that matches URLs to Razor components so that the correct view can be rendered to the browser.

In most web development frameworks, there is usually a one-to-one correlation between the URL and the physical location of the resource to be rendered such as the file name and path of the page or view. This pattern is used in the ASP.NET Web Forms, Web Pages and .NET Core Razor Pages frameworks. In ASP.NET MVC, the default convention is to match segments of the URL to the names of a controller and action method. There is no such name matching convention in Blazor. Instead, URLs are matched to a collection of predefined routes which are defined within the component itself.

Razor components that act as navigable endpoints or pages in a Blazor application must have either

  • an @page directive followed by a route template, or
  • an @attribute directive followed by a RouteAttribute that takes a constant representing a route template

A route template is a string that specifies the pattern for a route that the page can be reached at. At application startup, these templates are used to build a collection of Attribute Routes that match a URL to a component. Attribute routing is widely used in many other parts of ASP.NET. In Blazor applications, the template must relative to the root of the application and begin with a forward slash (/).

Often, the template consists solely of literal text, resulting in a one-to-one match between the incoming URL and the route template. In the following example, the route template "/about" is defined as part of the @page directive. The component is rendered when the user navigates to /about:

@page "/about"

<h1>About Us</h1> 

Here is the same example with a route attribute instead:

@attribute [Route(Constants.AboutRoute)]

<h1>About Us</h1> 

Constants.AboutRoute is defined as a constant value elsewhere within the application:

public static class Constants
{
    public const string AboutRoute = "/about";
}

You can specify multiple routes templates for a single component via additional @page directives or Route attributes:

@attribute [Route(Constants.AboutRoute)]
@page "/about-us"

<h1>About Us</h1>

This component will be rendered if the user navigates to /about or /about-us

Note

The forward slash (/) is required at the start of a route template in Blazor. But if you are working with Razor Pages, you should be aware of how a forward slash changes the behaviour of routing there. When a forward slash is included at the start of a Razor Page route template, the template overrides the default route, which is based on the file name and path of the Razor page.

The default page for a Blazor application is located at "/". In the standard project template, this is applied to the Home.razor component (the Index.razor component in earlier versions). But you can change that to any file you like.

Route Parameters

Route parameters are placeholders for values that you want to pass to a specific component via the URL. The place holder is represented in a route template as a token within curly braces: { token }. The token or parameter name must match a public property within the component that is decorated with the [Parameter] attribute. In the next listing, the route parameter is named id, and the component includes a parameter with the same name (case-insensitive):

@page "/details/{id}"
<h1>Details</h1>

@code{
    [Parameter] public string Id { get; set; }
}

Blazor will bind the parameter value to the public property automatically.

The data type of the public property is a string. By default, all route data values are strings. Changing the property data type alone will result in a System.InvalidOperationException, with the message:

Unable to set property 'id' on object of type '[name of the component]'. The error was: Specified cast is not valid.

If you want to work with different types, you must apply a constraint to the parameter in the route template. You do this by adding a colon, followed by the data type that you want to work with:

@page "/details/{id:int}"

<h1>Details</h1>

@code{
    [Parameter] public int Id { get; set; }
}

Attribute routing supports a large number of constraints, but Blazor only supports a subset of them:

Constraint Description Example
bool Matches a Boolean value. {isActive:bool}
int Matches a 32-bit integer value. {id:int}
datetime Matches a DateTime value. {startdate:datetime}
decimal Matches a decimal value. {cost:decimal}
double Matches a 64-bit floating-point value. {latitude:double}
float Matches a 32-bit floating-point value. {x:float}
long Matches a 64-bit integer value. {x:long}
guid Matches a GUID value. {id:guid}

Optional Parameters

Optional parameters, supported in other parts of ASP.NET Core (MVC and Razor Pages), are not supported in Blazor. If you want to be able to navigate to a component without providing a value for a route parameter, you should specify an alternative route within the component that doesn't include the parameter placeholder:

@page "/details
@page "/details/{id:int}"

<h1>Details</h1>

@code{
    [Parameter] public int Id { get; set; }
}

You can also provide alternative route templates that differ only by data type:

@page "/details
@page "/details/{id:int}"
@page "/details/{title}" // string data type

<h1>Details</h1>

@code{
    [Parameter] public int Id { get; set; }
    [Parameter] public string Title { get; set; }
}

The Router Component

The Router component is responsible for locating the correct component based on the current URL. You will find it in the App component in the project template:

<Router AppAssembly="@typeof(App).Assembly">
    <Found Context="routeData">
        <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
        <FocusOnNavigate RouteData="@routeData" Selector="h1" />
    </Found>
    <NotFound>
        <PageTitle>Not found</PageTitle>
        <LayoutView Layout="@typeof(MainLayout)">
            <p role="alert">Sorry, there's nothing at this address.</p>
        </LayoutView>
    </NotFound>
</Router>

The AppAssembly parameter value specifies the assembly to be searched for page components (those with an @page directive or RouteAttribute) that might match the current URL. By default, it specifies the current assembly. If you have page components in numerous assemblies, you can specify those via the AdditionalAssemblies parameter which takes an IEnumerable<Assembly> as an argument.

The Router Component has two child content parameters: Found and NotFound. These are responsible for displaying content based on whether a component matching the route was found. If a page component is found, the RouteView component renders the content of the page, using the layout specified in the DefaultLayout parameter (unless the page component specifies an alternative layout). If no matching component is found, the NotFound content is displayed. The default project template displays the message "Sorry, there's nothing at this address" within the MainLayout component. You can customise this as desired.

Last updated: 11/22/2024 8:12:13 AM

Latest Updates

© 2023 - 2024 - Mike Brind.
All rights reserved.
Contact me at Mike dot Brind at Outlook.com