Validate URL parameter in Blazor and respond with 404

Viewed 539

I'm trying to validate the URL in a Blazor server-side page. The parameter value needs to be a value in an enum. If the URL value isn't one of the enum values, I'd like to return an HTTP response 404.

I realise that Blazor's way of handling stuff is a bit different from vanilla ASP.NET, so I'm not even sure this is possible. The examples I've managed to find all navigate to a 'not found' page. That might work, but I'd prefer a 404 error.

Here's an example to illustrate what I'm trying to do.

page "/{Value?}"

<h1>@ParsedValue.ToString()</h1>

@code {
    [Parameter]
    public string Value { get; set; }

    public MyEnum ParsedValue { get; private set; }

    protected override void OnParametersSet()
    {
        if (!string.IsNullOrEmpty(Value))
        {
            MyEnum parsedValue;
            if (!Enum.TryParse<MyEnum>(Value, out parsedValue))
            {
                // return 404 not found
            }
            ParsedValue = parsedValue;
        }
        base.OnParametersSet();
    }

    public enum MyEnum
    {
        Apples,
        Oranges,
        Bananas
    }
}
1 Answers

You could navigate to a 404 page.

In your component, you can use NavigateTo with the forceLoad option - this avoids the Blazor router.

@inject NavigationManager navman
@page "/{Value?}"

<h1>@ParsedValue.ToString()</h1>

@code {
    [Parameter]
    public string Value { get; set; }

    public MyEnum ParsedValue { get; private set; }

    protected override void OnParametersSet()
    {
        if (!string.IsNullOrEmpty(Value))
        {
            MyEnum parsedValue;
            if (!Enum.TryParse<MyEnum>(Value, out parsedValue))
            {
                navman.NavigateTo($"404?{navman.Uri}",true);
            }
            ParsedValue = parsedValue;
        }
        base.OnParametersSet();
    }

    public enum MyEnum
    {
        Apples,
        Oranges,
        Bananas
    }
}

Then map an endpoint to handle the 404 route in startup.cs

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers();
    endpoints.MapBlazorHub();
    endpoints.Map("404", rq =>
    {                    
        rq.Response.StatusCode = 404;
        rq.Response.WriteAsync(Get404(rq.Request.QueryString.ToString().Substring(5)));
        return Task.CompletedTask;
    });
    endpoints.MapFallbackToPage("/_Host");
});
string Get404(string url)
{
    return $@"
        <h1>404 - Page not found</h1>
        <p>{url}</p>
        <a href=""/"">Home</a>
        ";
}

If you wanted a Razor page to handle the display of the 404 message instead of an actual 404 status response, you could also use app.UseStatusCodePagesWithRedirects to redirect that 404 to an actual Razor page/View to make things pretty - but then you could have had that within the Blazor SPA, so I doubt you want that - you did ask for a true 404.

Related