简体   繁体   中英

Custom json response body for HTTP errors

I'm wondering if there is a way in API Controllers to return a custom object as response body for methods like: BadRequest() or NotFound() .

For example, for 404 error, I'd like to return something like:

{
  "StatusCode": 404,
  "Error": "Not Found",
  "Message": "Custom message..."
}

Instead I'm getting this:

{
  "Message": "Custom message..."
}

At the moment to return complex response body I'm using Ok() this way:

return Ok(new
{
    Success = false,
    Message = "Custom message...",
    // other fields...
});

But obviously I'm returning a 200 status that is not so meaningful.

Is there a better way to achieve this?

Long Way

If you need a quick solution just jump to Short Way , read this just to understand how it works under the hood. Derive your own JsonErrorResult class derived from JsonResult :

public sealed JsonErrorResult : JsonResult
{
    public JsonErrorResult(StatusCodes statusCode, object value)
        : base(value)
    {
        _statusCode = statusCode;
    }

    private readonly JsonErrorResult StatusCodes _statusCode;
}

Now override ExecuteResultAsync() method to change status code of default JsonResult implementation:

public override Task ExecuteResultAsync(ActionContext context)
{
    context.HttpContext.Response.StatusCode = _statusCode;
    return base.ExecuteResultAsync(context);
}

You simply return calling BadRequest() you simply do this:

return new JsonErrorResult(StatusCodes.Status400BadRequest, new 
{
    StatusCode = "404",
    Error = "bla bla bla",
    Message = "bla bla bla"
});

Of course if you use it often you may want to create your own helper method:

protected static JSonErrorResult JsonError(StatusCodes statusCode,
                                           string error, string message)
{
    return new JsonErrorResult(statusCode, new 
    {
        StatusCode = Convert.ToString((int)statusCode),
        Error = error,
        Message = message
    });
}

Used like this:

return JsonError(StatusCodes.Status400BadRequest, "bla bla bla", "bla bla bla");

Short Way

JsonResult already has StatusCode property then your helper method may become like this:

protected static JSonResult JsonError(StatusCodes statusCode,
                                           string error, string message)
{
    var result = new JsonResult(new 
    {
        StatusCode = Convert.ToString((int)statusCode),
        Error = error,
        Message = message
    });

    result.StatusCode = (int)statusCode;

    return result;
}

I usually return something like this:

return Json(new { success = false, data = "" }, JsonRequestBehavior.AllowGet);

And then in my AJAX success, I do:

if(result.success){
    result.data...
}else{
    //error...
}

If you do not want to always send a 200 code, then can you do something like this?

//if success...
Response.StatusCode = 200;
return Json(new { responseCode = 200, data = "", message = "..." }, JsonRequestBehavior.AllowGet);

//if failure...
Response.StatusCode = 404;
return Json(new { responseCode = 404, data = "", message = "..." }, JsonRequestBehavior.AllowGet);

Create function to deal with error.

function AjaxCompletion(xhr) {
    switch (xhr.status) {
        case 200:
            //Your Message
            break;
        case 401: //unauthorize
           //Your desire message
            break;
    }
}

And in AJAX complete :

  complete: function (xhr) {
            AjaxCompletion(xhr);
        }

Thanks for your code, it worked (after a while). It seems that you have written pseudo-code rather than code itself. So, in order to make life easier to other, here is your same exact code but withing a class which runs.

public sealed class JsonErrorResult : JsonResult {

    private readonly HttpStatusCode _statusCode;

    public JsonErrorResult(HttpStatusCode sCode, object value) : base(value) {
        _statusCode = sCode;
    }

    public override Task ExecuteResultAsync(ActionContext context) {
        context.HttpContext.Response.StatusCode = (int)_statusCode;
        return base.ExecuteResultAsync(context);
    }

    public static JsonResult JsonError(HttpStatusCode statusCode,
                                               string message, string error = "") {
        var result = new JsonResult(new {
            StatusCode = Convert.ToString((int)statusCode),
            Error = error,
            Message = message
        });

        result.StatusCode = (int)statusCode;

        return result;
    }
}

and finally you call it like so:

return JsonErrorResult.JsonError(System.Net.HttpStatusCode.Unauthorized,
                                "error msg");

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM