NathanAldenSr NathanAldenSr - 2 months ago 20
C# Question

Custom response for 404s in MVC 6

I am migrating a Web API 2 application over to MVC 6 and I'm struggling to figure out how to return a custom response when status codes like 404 or 405 occur. In Web API, I used an

HttpMessageHandler
for 404 and a
DelegatingHandler
for 405.

I am aware of the concept of middleware, but it seems like the middleware isn't executing late enough in the pipeline to capture the 404. Also, generating responses in middleware is sub-optimal because the
HttpResponse
class only exposes raw HTTP parameters like
ContentLength
and
Body
. I would prefer to simply return an
IActionResult
that contains a custom response model like all my regular endpoints do.

Startup code:

applicationBuilder.UseMiddleware<NotFoundMiddleware>();
applicationBuilder.UseMvc();


Middleware:

public class NotFoundMiddleware
{
private readonly RequestDelegate _next;

public NotFoundMiddleware(RequestDelegate next)
{
_next = next.EnsureNotNull(nameof(next));
}

public Task Invoke(HttpContext context)
{
if (context.Response?.StatusCode == StatusCodes.Status404NotFound)
{
// context.Response.StatusCode is 200 because context.Response is set to an instance of DefaultHttpResponse
}

return _next.Invoke(context);
}
}


Is there a good way of accomplishing what I need?

Answer

Rearrange how you are executing your logic

public class NotFoundMiddleware {
    private readonly RequestDelegate _next;

    public NotFoundMiddleware(RequestDelegate next) {
        _next = next.EnsureNotNull(nameof(next));
    }

    public async Task Invoke(HttpContext context) {
        //let the context go through the pipeline
        await _next.Invoke(context);

        if (context.Response?.StatusCode == StatusCodes.Status404NotFound) {
           //execute your logic on the way out of the pipeline.
        }

    }
}

and also make sure that you register it early in the pipeline