Is it possible to return { } instead of null when webApi returns a null object? This, to prevent my user from getting errors while parsing the response. And to make the respon
Thanks to Darrel Miller, I for now use this solution.
WebApi messes with StringContent "{}" again in some environment, so serialize through HttpContent.
/// <summary>
/// Sends HTTP content as JSON
/// </summary>
/// <remarks>Thanks to Darrel Miller</remarks>
/// <seealso cref="http://www.bizcoder.com/returning-raw-json-content-from-asp-net-web-api"/>
public class JsonContent : HttpContent
{
private readonly JToken jToken;
public JsonContent(String json) { jToken = JObject.Parse(json); }
public JsonContent(JToken value)
{
jToken = value;
Headers.ContentType = new MediaTypeHeaderValue("application/json");
}
protected override Task SerializeToStreamAsync(Stream stream, TransportContext context)
{
var jw = new JsonTextWriter(new StreamWriter(stream))
{
Formatting = Formatting.Indented
};
jToken.WriteTo(jw);
jw.Flush();
return Task.FromResult<object>(null);
}
protected override bool TryComputeLength(out long length)
{
length = -1;
return false;
}
}
Derived from OkResult to take advantage Ok() in ApiController
public class OkJsonPatchResult : OkResult
{
readonly MediaTypeWithQualityHeaderValue acceptJson = new MediaTypeWithQualityHeaderValue("application/json");
public OkJsonPatchResult(HttpRequestMessage request) : base(request) { }
public OkJsonPatchResult(ApiController controller) : base(controller) { }
public override Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
var accept = Request.Headers.Accept;
var jsonFormat = accept.Any(h => h.Equals(acceptJson));
if (jsonFormat)
{
return Task.FromResult(ExecuteResult());
}
else
{
return base.ExecuteAsync(cancellationToken);
}
}
public HttpResponseMessage ExecuteResult()
{
return new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new JsonContent("{}"),
RequestMessage = Request
};
}
}
Override Ok() in ApiController
public class BaseApiController : ApiController
{
protected override OkResult Ok()
{
return new OkJsonPatchResult(this);
}
}
If you are building a RESTful service, and have nothing to return from the resource, I believe that it would be more correct to return 404 (Not Found) than a 200 (OK) response with an empty body.
You can use a HttpMessageHandler
to perform behaviour on all requests. The example below is one way to do it. Be warned though, I whipped this up very quickly and it probably has a bunch of edge case bugs, but it should give you the idea of how it can be done.
public class NullJsonHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var response = await base.SendAsync(request, cancellationToken);
if (response.Content == null)
{
response.Content = new StringContent("{}");
} else if (response.Content is ObjectContent)
{
var objectContent = (ObjectContent) response.Content;
if (objectContent.Value == null)
{
response.Content = new StringContent("{}");
}
}
return response;
}
}
You can enable this handler by doing,
config.MessageHandlers.Add(new NullJsonHandler());
Maybe better solution is using Custom Message Handler.
A delegating handler can also skip the inner handler and directly create the response.
Custom Message Handler:
public class NullJsonHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var updatedResponse = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = null
};
var response = await base.SendAsync(request, cancellationToken);
if (response.Content == null)
{
response.Content = new StringContent("{}");
}
else if (response.Content is ObjectContent)
{
var contents = await response.Content.ReadAsStringAsync();
if (contents.Contains("null"))
{
contents = contents.Replace("null", "{}");
}
updatedResponse.Content = new StringContent(contents,Encoding.UTF8,"application/json");
}
var tsc = new TaskCompletionSource<HttpResponseMessage>();
tsc.SetResult(updatedResponse);
return await tsc.Task;
}
}
Register the Handler:
In Global.asax
file inside Application_Start()
method register your Handler by adding below code.
GlobalConfiguration.Configuration.MessageHandlers.Add(new NullJsonHandler());
Now all the Asp.NET Web API
Response which contains null
will be replaced with empty Json
body {}
.
References:
- https://stackoverflow.com/a/22764608/2218697
- https://docs.microsoft.com/en-us/aspnet/web-api/overview/advanced/http-message-handlers