How to manually display the Blazor-Webassembly-404-Not-Found page if a route matches but the parameters are wrong?

Viewed 381

Imagine, this is the route to my Blazor page: @page "/a/b/c/{numericvalue:int}"

The following requests would match:

/a/b/c/1
/a/b/c/2
/a/b/c/509

This request...

/a/b/c/test

... would display the NotFound page defined in the App.razor file:

<NotFound>
    <LayoutView Layout="@typeof(MainLayout)">
        <p>Sorry, there's nothing at this address.</p>
    </LayoutView>
</NotFound>

But now I want odd number to be rejected, too. How can I display the NotFound page manually after I found out that the number is odd? My code looks like this:

@code{
    [Parameter]
    public int NumericValue {
        set => {
            if(value % 2 == 1)
                // show the 404 page
        }
    }
}
1 Answers

I've looked into this out of curiosity, and my first approach would be making a custom IRouteConstraint like you would in MVC. However, the route constraints don't work in Blazor and a look at the source code reveals that the Router component has a hard-coded list of route constraints for the pages.

I came up with a work-around however, and if you do not have a massive amount of these custom constraints then I suppose this is a workable solution. What you do is insert some custom logic into the Found section of the Router and redirect the rendered output to NotFound according to your own conditional flow.

The following modified App.razor will ensure that the Number route parameter for the Even page is always an even number and will show the NotFound content if it's an odd number:

<Router AppAssembly="@typeof(Program).Assembly" PreferExactMatches="@true" NotFound="NotFound">
    <Found Context="routeData">
        @{
            bool found = true;
            var route = routeData;

            if (routeData.PageType.IsEquivalentTo(typeof(Pages.Even)))
            {
                if (routeData.RouteValues.TryGetValue("number", out var numberValue))
                {
                    var number = Convert.ToInt32(numberValue);

                    if (number % 2 != 0)
                    {
                        found = false;
                    }
                }
            }
        }
        @if (found)
        {
            <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
        }
        else
        {
            @NotFound
        }
    </Found>
</Router>
@code
{
    private RenderFragment NotFound => __builder =>
    {
        <LayoutView Layout="@typeof(MainLayout)">
            <p>Sorry, there's nothing at this address.</p>
        </LayoutView>
    };
}
Related