3

I have a project I want to use as both a Web API, and as a Blazor wasm UI. This API will also be accessed from other projects, so I want the API to provide useful error details to the consumers.

I have the site working towards both purposes right now by using the MapFallbackToFile() method, however if you try to make a POST to an endpoint that only accepts GET, you get a 404 in response, instead of a 405 for an invalid http method.

I'm using the solution provided in this question in order to map only non-api paths, but this always gives 404s, and I'm worried it would hide any other potential issue with the request.

How can I get the HandleApiFallback() method to simply behave as a Web API normally would, while still excluding the /api/ paths from serving blazor pages?


app.UseEndpoints(endpoints =>
{
    endpoints.MapRazorPages();
    endpoints.MapControllers();
    endpoints.Map("api/{**slug}", HandleApiFallback);
    endpoints.MapFallbackToFile("{**slug}", "index.html");
});

private Task HandleApiFallback(HttpContext context)
{
    context.Response.StatusCode = StatusCodes.Status404NotFound;
    return Task.CompletedTask;
}

Example Integration test:

    var response = client.GetAsync(path).GetAwaiter().GetResult();
    response.StatusCode.Should().Be(HttpStatusCode.OK);

    var response2 = client.PostAsJsonAsync(path, "").GetAwaiter().GetResult();
    response2.StatusCode.Should().Be(HttpStatusCode.MethodNotAllowed);

When you have any MapFallbackToFile() used, the second assertion fails as a 404 instead of a 405.

DLeh
  • 23,806
  • 16
  • 84
  • 128

1 Answers1

3

I found a solution by looking at a case where you might want multiple blazor apps running at differectories, and modified it to fit my use case:


//explicitly only use blazor when the path doesn't start with api
app.MapWhen(ctx => !ctx.Request.Path.StartsWithSegments("/api"), blazor =>
{
    blazor.UseBlazorFrameworkFiles();
    blazor.UseStaticFiles();

    blazor.UseRouting();
    blazor.UseEndpoints(endpoints =>
    {
        endpoints.MapFallbackToFile("index.html");
    });
});

//explicitly map api endpoints only when path starts with api
app.MapWhen(ctx => ctx.Request.Path.StartsWithSegments("/api"), api =>
{
    //if you are not using a blazor app, you can move these files out of this closure
    api.UseStaticFiles();
    api.UseRouting();
    api.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
        endpoints.MapControllers();
    });
});

This passes the integration test I mentioned, so that I get the correct 405 error when I try to use the wrong HTTP method against an API, rather than a 404.

DLeh
  • 23,806
  • 16
  • 84
  • 128