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 aRouteAttribute
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 Index.razor file. 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.