leejt489 leejt489 - 3 months ago 24
ASP.NET (C#) Question

Modify .NET ApiController "BadResult()" to print custom JSON

I am using the .NET pattern where my controller action has a signature as such

public async Task<IHttpActionResult> GetTimeSeries(string deviceId, string tag) { ... }


and inside the controller I want to send a custom error message adhering to the JSON API Spec

My goal is when encountering an error to use

return BadRequest(someJSONErrorObject);


or

return NotFound(someJSONErrorObject);


rather than throw an exception.

Currently if I do

return BadRequest(JsonConvert.SerializeObject(someJSONErrorObject));


the JSON I get back looks like

{
"Message": "{\"data\":null,\"errors\":[{\"detail\":\"The string was not recognized as a valid DateTime. There is an unknown word starting at index 0.\"}],\"meta\":null}"
}

Answer

Create a custom IHttpActionResult

public class CustomResponseResult<T> : IHttpActionResult {

    public CustomResponseResult(HttpStatusCode statusCode, T content, HttpRequestMessage request) {
        Content = content;
        Request = request;
        StatusCode = statusCode;
    }

    public T Content { get; private set; }
    public HttpRequestMessage Request { get; private set; }
    public HttpStatusCode StatusCode { get; private set; }

    public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken) {
        return Task.FromResult(Execute());
    }

    private HttpResponseMessage Execute() {
        var response = Request.CreateResponse(StatusCode, Content);
        response.RequestMessage = Request;
        response.ReasonPhrase = StatusCode.ToString();
        return response;
    }
}

and then in order to maintain usability create extension methods

public static class ApiControllerExtensions {
    public static IHttpActionResult BadRequest<T>(this ApiController controller, T content) {
        return controller.CustomResponse(HttpStatusCode.BadRequest, content);
    }

    public static IHttpActionResult NotFound<T>(this ApiController controller, T content) {
        return controller.CustomResponse(HttpStatusCode.NotFound, content);
    }

    public static IHttpActionResult CustomResponse<T>(this ApiController controller, HttpStatusCode statusCode, T content) {
        var request = controller.Request;
        var result = new CustomResponseResult<T>(statusCode, content, request);
        return result;
    }
}

that allowed the calls wanted

return this.BadRequest(someJSONErrorObject);

or

return this.NotFound(someJSONErrorObject);