Blazor comes with a router out of the box, similar to other SPA applications such as Angular. While the Blazor router is much simpler than those found in other frameworks, you can already build useful multi-page apps.
How does the router in Blazor actually work?
Blazors router is just another component and implements IComponent
the same as any other. Currently it takes an AppAssembly
parameter which is the assembly for the Blazor application.
The router uses the provided AppAssembly
to find the component which matches the URL of the current request, then it loads that component.
Route Templates
In Blazor, you define routes using route templates. You can define a route template by adding the @page
directive to the top of a component.
@page "/home"
<h1>Hello World</h1>
The above component would be loaded when the user navigated to www.mydomaim.com/home.
If you are defining your component as a pure C# class then you can specify its route template by decorating it with the route attribute, [RouteAttribute("/home")]
. Which is ultimately what the @page
directive gets compiled to.
It’s also valid to specify multiple route templates for a component. You can achieve this by defining multiple @page
directives or [RouteAttributes]
.
@page "/"
@page "/home"
<h1>Hello World</h1>
Route Parameters
The example above is fine for simple routes but what if you need to pass some data via the URI? For example, you have a product component that needs a product id to load that products information. That is where route parameters come in.
When defining a route template you can use curly brackets to include a parameter, @page "/products/{ProductId}"
. This parameter is then assigned to a property of the same name on the component.
@page "/products/{ProductId}"
@inject IProductService ProductService
...
@code {
[Parameter] public int ProductId { get; set; }
private Product product;
protected override async Task OnInitAsync()
{
product = await ProductService.GetProduct(ProductId);
}
}
Similar too routes in ASP.NET Core, you can also define route constraints on route parameters. In the example above you may wish to enforce that the ProductId
was an int
. In order to achieve this you could change the route template as follows, @page "/products/{ProductId:int}"
.
If someone then tried to navigate to this component with a URI like /products/foo then the router would not match the route with the above component. The currently supported types for enforcement are:
bool
datetime
decimal
double
float
guid
int
long
Linking Pages
There are three ways to link pages, one is to use regular a
tags, another is to use the NavLink
component, the last is programmatically.
To use traditional a
tags you just have to specify the relative URI to the page you wish to link to. You will need to have a base
tag defined in your index.html
, but if you are using one of the Blazor templates this is already done for you. Then Blazors router will automatically handle navigation for you without causing any postbacks.
The next option is to use the NavLink
component provided by Blazor. It takes a href
as a parameter which it then uses to render a standard a
tag. But whats really useful is that when the current URI matches the href
it will add an active class to the link.
<!-- Defining link -->
<NavLink href="/home">
Home
</NavLink>
<!-- Rendered link not matching current URI -->
<a class="null" href="/home">Home</a>
<!-- Rendered link matching current URI -->
<a class="active" href="/home">Home</a>
You can also define a Match
parameter on a NavLink
which tells the component how to decide if the current URI matches the href
. There are currently two options available. All
and Prefix
.
All
is the default and tells the NavLink
component to apply the active
class only when the whole URI matches. The second option is Prefix
and this tells the NavLink
component to apply the active
class when the prefix of the current URI matches.
This is useful when you have a menu with sub sections where you may wish to apply styling to the section link and the currently active sub-section link.
<NavLink href="/expenses" Match=NavLinkMatch.Prefix>Expenses</NavLink>
<NavLink href="/expenses/shopping" Match=NavLinkMatch.All>Shopping</NavLink>
<NavLink href="/expenses/bills" Match=NavLinkMatch.All>Bills</NavLink>
<NavLink href="/expenses/groceries" Match=NavLinkMatch.All>Groceries</NavLink>
In this example, when the /expenses/bills URI was requested both the Expenses and Bills links would have the active
class applied.
The final way to is to navigate programmatically. In order to do this you will need to use NavigationManager
. This helper contains a few handy methods but the one we’re interested in is NavigateTo
. This method takes a string, which is the URI to navigate to, then performs the navigation.
NavigationManager.NavigateTo("/home");
In order to use it you will need to inject it into your component or service. To inject into a component you can either use the @inject
directive, or the [Inject]
attribute.
@inject NavigationManager LocalNavigationManager
// C# only component
public class MyComponent : ComponentBase
{
[Inject]
protected NavigationManager LocalNavigationManager { get; set; };
...
}
If you need to use it from somewhere other than a component such as a service then you must use constructor injection.
public class MyService
{
private NavigationManager _navigationManager;
public MyService(NavigationManager navigationManager)
{
_navigationManager = navigationManager;
}
...
}
Summary
In this post, we started by understanding how Blazors router works. We then moved on to route templates and route parameters. We finished off with how to link pages together using either anchor tags, the NavLink
component or using NavigationManager
.