Optional Parameters in Razor Pages Routing

Razor Pages routing is based on attribute routing and is very powerful. Parameters provide a way of passing arbitrary data to a page via the URL. Optional parameters allow URLs to matched to routes even if no parameter value is passed. Things can get a bit complicated if you want to permit multiple optional parameters.

There are two ways of providing parameter values as part of the URL - as path segments (e.g. /yourpage/1) or as query string values (e.g. /yourpage?id=1). Query strings are fairly straightforward to work with. Path segments require configuration, which is normally done by supplying a route template to the @page directive in a Razor content page specifying the name of a route parameter:

@page "{id}"

You can specify the constraint for the data type that the value must match:

@page "{id:int}"

And you can use the ? syntax to indicate that the parameter value is not required:

@page "{id:int?}"

This will be matched by /yourpage and yourpage/2 but not yourpage/blah (because of the type constraint). But what if you have multiple optional parameters? Let's say that you have a report that can take either a start date or an end date as parameters, or both,  or neither:

@page "{startdate:datetime?}/{enddate:datetime?}"

This works fine when values for both parameters are provided e.g. /report/2019-1-1/2019-12-31. Both values are bound to PageModel properties:

Optional Route Parameters

If you provide just one value, e.g. /report/2019-1-1, it will always be bound to the first parameter:

Optional Route Parameters

So what are your options? At this stage, it helps if you start to equate routes to C# method signatures.

Method Overloading

You can overload C# methods, and you can do that same with routes in Razor Pages via the AddPageRoute method. However, in this example, overloading won't work because both parameters are the same data type. If you added a route that takes one datetime value representing the startdate, you can't add another to represent the endate value.

Default Values

What you can do instead is to change the first parameter so that it is no longer optional, and provide a default value:

@page "{startdate:datetime=2000-1-1}/{enddate:datetime?}"

This is a neat solution all the time that you are in control of how URLs are generated for this route. The anchor tag helper, for example, will populate the startdate with the default value if no value is provided:

<a asp-page="/report" asp-route-enddate="2019-12-31">View Report</a>

Optional Route Parameters

Named Parameters

When optional arguments were introduced in C# 4.0, the implementation also included named arguments as part of the package. If you want to skip an optional parameter, you can provide values for others that come after it in the parameter list by prefixing the value with the name of the argument. If Report was a C# method instead of a Razor page, you would call it like this when only providing an enddate value:

Report(enddate: new Date(2019,12,31));

You can implement the same approach by using query string values rather than path segments for data passed in URLs. To take advantage of this method, don't provide a route template to the @page directive. Any values provided to asp-route attributes will be assigned to query string values instead:

Optional Route Parameters

As long as your PageModel properties have SupportsGet=true applied to their BindProperty attribute, the value will be bound to the correct property:

Optional Route Parameters

Summary

Multiple optional parameters in Razor Pages URLs are one of those things that can cause a mental block. Once you start to think of them in the same way as arguments to C# methods, solutions are much easier to grasp.