Dave New
Dave New

Reputation: 40002

Custom 404 response model

I want to provide a custom reponse for all 404s on our API. For example:

{
  "message": "The requested resource does not exist. Please visit our documentation.."
}

I believe the following result filter works for all cases within the MVC pipeline:

public class NotFoundResultFilter : ResultFilterAttribute
{
    public override void OnResultExecuting(ResultExecutingContext context)
    {
        var result = context.Result as NotFoundResult;

        if (result != null)
        {
            context.Result = new HttpNotFoundResult(); // My custom 404 result object
        }
    }
}

But, when a URL requested does not match an action route, the above filter is not hit. How could I best intercept these 404 responses? Would this require middleware?

Upvotes: 4

Views: 2011

Answers (2)

HappyNomad
HappyNomad

Reputation: 4548

Try this:

app.Use( async ( context, next ) =>
{
    await next();

    if ( context.Response is { StatusCode: 404, Body: { Length: 0 }, HasStarted: false } )
    {
        context.Response.ContentType = "application/problem+json; charset=utf-8";
        string jsonString = JsonConvert.SerializeObject(errorDTO);
        await context.Response.WriteAsync( jsonString, Encoding.UTF8 );
    }
} );

Upvotes: 1

Set
Set

Reputation: 49779

Yes, you need to use middleware, as filter is only for MVC.

  1. You may, as always, write your own middleware

    app.Use(async (context, next) =>
    {
        await next();
        if (context.Response.StatusCode == 404)
        {
            context.Response.ContentType = "application/json";
    
            await context.Response.WriteAsync(JsonConvert.SerializeObject("your text"), Encoding.UTF8);
        }
    });
    
  2. Or use built-in middlware StatusCodePagesMiddleware, but as you want to handle only one status, this is an extra functionality. This middleware can be used to handle the response status code is between 400 and 600 .You can configure the StatusCodePagesMiddleware adding one of the following line to the Configure method (example from StatusCodePages Sample):

    app.UseStatusCodePages(); // There is a default response but any of the following can be used to change the behavior.
    
    // app.UseStatusCodePages(context => context.HttpContext.Response.SendAsync("Handler, status code: " + context.HttpContext.Response.StatusCode, "text/plain"));
    // app.UseStatusCodePages("text/plain", "Response, status code: {0}");
    // app.UseStatusCodePagesWithRedirects("~/errors/{0}"); // PathBase relative
    // app.UseStatusCodePagesWithRedirects("/base/errors/{0}"); // Absolute
    // app.UseStatusCodePages(builder => builder.UseWelcomePage());
    // app.UseStatusCodePagesWithReExecute("/errors/{0}");
    

Upvotes: 9

Related Questions