Stanislav Angelov
Stanislav Angelov

Reputation: 21

How to use Middleware to overwrite response body on 405 - MethodNotAllowed

I am porting an API from .NET to .NET Core. For the task every response needs to be the same. In the case where I try a "PUT" request on a "GET" only endpoint the old API returns the following in Postman with status code 405:

{
"Message": "The requested resource does not support http method 'PUT'."}

.NET Core by default returns empty body with 405.

My question is how to emulate the response body of the first example in .NET CORE.

My current attempts led me to creating a middle-ware which is added before app.UseRouting();. The middleware looks like this: public class MethodNotAllowedMiddleware { private RequestDelegate _next;

    public MethodNotAllowedMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        await _next(context);

        if(context.Response.StatusCode == (int)HttpStatusCode.MethodNotAllowed)
        {
            await context.Response.WriteAsync("The requested resource does not support http method 'PUT'.");//This will NOT be hardcoded string
        }
    }
}

However the response body is plain string and not in JSON format. How could I build the response with proper classes instead of hard-coding a string? I am thinking that this is a very hacky solution, and that there should be a more elegant way to solve the problem that I am missing.

Upvotes: 0

Views: 1240

Answers (2)

Stanislav Angelov
Stanislav Angelov

Reputation: 21

I was on the right track, I was missing setting the response StatusCode, Content-Type and serialized JSON for the response Body.

After adjustments the body of the middleware looks like this: await _next(context);

        if (context.Response.StatusCode == (int)HttpStatusCode.MethodNotAllowed && context.Response.HasStarted == false)
        {
            //Assign the error message
            MiddlewareErrorMessage msg = new MiddlewareErrorMessage($"The requested resource does not support http method '{context.Request.Method}'.");
            // Set the status code
            context.Response.StatusCode = 405;
            // Set the content type
            context.Response.ContentType = "application/json; charset=utf-8";
            string jsonString = JsonConvert.SerializeObject(msg);
            await context.Response.WriteAsync(jsonString, Encoding.UTF8);
        }

Where "MiddlewareErrorMessage" simply has the structure of the error I want to return

Upvotes: 0

Michael Shterenberg
Michael Shterenberg

Reputation: 1016

See custom error handling here: https://joonasw.net/view/custom-error-pages

You can re-route to a new path and use MVC to create any object/page you want:

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

    if (ctx.Response.StatusCode == 405 && !ctx.Response.HasStarted)
    {
        //Re-execute the request so the user gets the error page
        string originalPath = ctx.Request.Path.Value;
        ctx.Items["originalPath"] = originalPath;
        ctx.Request.Path = "/Home/Error405";
        await next();
    }
});

And you controller code:

public class HomeController : Controller
{
    [AllowAnonymous]
    public IActionResult Error405()
    {
        return new ObjectResult(new Response { 
           Message = "The requested resource does not support http method 'PUT'."
        }) {
            StatusCode = 405
        };
    }

    public class Response
    {
        public string Message { get; set; }
    }
}
  • Make sure to wrap AllowAnonymous to disable the authorization flow

Upvotes: 1

Related Questions