Вернуть пустой json на null в WebAPI

Можно ли возвращать {} вместо null, когда webApi возвращает нулевой объект? Это, чтобы мой пользователь не получал ошибок при анализе ответа. И чтобы сделать ответ действительным Json Response?

Я знаю, что я могу настроить его везде вручную. То, что когда null является ответом, должен быть возвращен пустой объект Json. Но есть ли способ сделать это автоматически для каждого ответа?

Ответ 1

Если вы создаете службу RESTful и не можете ничего не возвращать из ресурса, я считаю, что было бы вернее возвращать 404 (не найдено), чем 200 (OK) с пустым телом.

Ответ 2

Вы можете использовать HttpMessageHandler для выполнения поведения по всем запросам. Пример ниже - это один из способов сделать это. Однако будьте осторожны, я быстро взбивал это, и у него, вероятно, есть куча ошибок на грани, но он должен дать вам представление о том, как это можно сделать.

  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;
        }
    }

Вы можете включить этот обработчик, выполнив

config.MessageHandlers.Add(new NullJsonHandler());

Ответ 3

Спасибо Даррел Миллер, я сейчас использую это решение.


WebApi беспорядок с StringContent "{}" снова в некоторой среде, поэтому сериализуем через 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;
    }
}

Производится из OkResult, чтобы использовать Ok() в 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
        };
    }
}

Переопределить Ok() в ApiController

public class BaseApiController : ApiController
{
    protected override OkResult Ok()
    {
        return new OkJsonPatchResult(this);
    }
}