3

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?

Dave New
  • 38,496
  • 59
  • 215
  • 394

2 Answers2

8

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}");
    
Set
  • 47,577
  • 22
  • 132
  • 150
  • Thanks! I don't believe the middleware can work like that because HttpContext doesn't not have a Result property. I believe UseStatusCodePages() might not be suited since I want to return JSON. – Dave New Jul 09 '16 at 07:51
  • Works great with 404s. I can't seem to get it to work with 401 or 403s when using JwtBearerAuthentication middleware, but i'll raise this in another question. – Dave New Jul 09 '16 at 10:48
  • I've asked the question here http://stackoverflow.com/questions/38281116/custom-401-and-403-response-model-with-usejwtbearerauthentication-middleware – Dave New Jul 09 '16 at 11:00
0

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 );
    }
} );
HappyNomad
  • 4,458
  • 4
  • 36
  • 55