Blazor University Learn the .NET SPA framework from Microsoft
Ctrl X

Optional route parameters

Optional route parameters aren't supported explicitly by Blazor, but the equivalent can be easily achieved by adding more than one @page declaration on a component. For example, alter the standard Counter.razor page to add an additional URL.

@page "/counter"
@page "/counter/{CurrentCount:int}"

Change the int currentCount field to a parameter, like so
[Parameter] public int CurrentCount { get; set; }

And then replace all references to currentCount with CurrentCount. Also add a few navigations on the page so we can quickly test our routes

@page "/counter"
@page "/counter/{CurrentCount:int}"

<h1>Counter</h1>

<p>Current count: @CurrentCount</p>

<button class="btn btn-primary" @onclick=IncrementCount>Click me</button>

<ul>
  <li><a href="/counter/42">Navigate to /counter/42</a></li>
  <li><a href="/counter/123">Navigate to /counter/123</a></li>
  <li><a href="/counter/">Navigate to /counter</a></li>
</ul>

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

  void IncrementCount()
  {
    CurrentCount++;
  }
}

When we run this app we see we can navigate either to /counter (no parameter required) or /counter/AnyNumber (parameter value specified). When no value is specified in the URL the default value for the property type will be used.

Specifying a default value for optional parameters

What if we want the default value of our parameter to be something other than the C# default? For example, when no value for CurrentCount is specified, we might want it to default to 1 instead of 0.

Firstly, we'll need to change the type of our parameter property to be nullable, so we can tell the difference between /counter/0 and just /counter - and then assign the default value to the property if it is null.

[Parameter]
public int? CurrentCount { get; set; }

protected override void OnInitialized()
{
  base.OnInitialized();
  CurrentCount = CurrentCount ?? 1;
}

At first this would seem to work, navigating to /counter will in fact default our CurrentCount value to 1.

However, this only works the first time the page is displayed. If we now navigate to /counter using one of the links without first navigating to another page (such as Home) we'll see the CurrentCount defaults to null.

When the component is a @page and our Blazor app navigates to a new URL that renders the same page, Blazor does not create a new instance of the component in order to render the page but instead it treats it as the same page with changed parameters. Because of this OnInitialized will be executed only when the page is first created. See Component lifecycles for details.

Previous URL Current URL Counter.OnInit executed
/ /counter Yes - Different page
/counter /counter/42 No - Same page
/counter/42 counter/123 No - Same page
/counter/123 /counter No - Same page
/counter /counter123 No - Same page
/counter123 /counter No - Same page
/counter / Yes - Different page

The correct solution is to default the value in SetParametersAsync - which is called whenever the parameters change and their values are pushed into the component's properties, such as during a navigation.

[Parameter]
public int? CurrentCount { get; set; }

public async override Task SetParametersAsync(ParameterView parameters)
{
  await base.SetParametersAsync(parameters);
  CurrentCount = CurrentCount ?? 1;
}