web-dev-qa-db-fra.com

Renvoie un json vide sur null dans l'API Web

Est-il possible de retourner {} au lieu de null lorsque webApi renvoie un objet null? Ceci, pour empêcher mon utilisateur d’obtenir des erreurs lors de l’analyse de la réponse. Et pour que la réponse soit une réponse Json valide?

Je sais que je pourrais le régler partout manuellement. Que lorsque null est la réponse, un objet Json vide doit être renvoyé. Mais, y a-t-il un moyen de le faire automatiquement pour chaque réponse?

14
spons

Si vous créez un service RESTful et que vous n’avez rien à retourner de la ressource, je pense qu’il serait plus correct de renvoyer 404 (Introuvable) qu'un 200 (OK) réponse avec un corps vide.

15
Mark Seemann

Vous pouvez utiliser une HttpMessageHandler pour effectuer le comportement sur toutes les demandes. L'exemple ci-dessous est une façon de le faire. Soyez averti cependant, j'ai corrigé cela très rapidement et il y a probablement beaucoup de bogues dans les cas Edge, mais cela devrait vous donner une idée de la façon dont cela peut être fait.

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

Vous pouvez activer ce gestionnaire en faisant,

config.MessageHandlers.Add(new NullJsonHandler());
8
Darrel Miller

Une meilleure solution

Peut-être la meilleure solution utilise-t-elle le gestionnaire de messages personnalisé.

Un gestionnaire de délégation peut également ignorer le gestionnaire interne et directement créer la réponse.

Gestionnaire de messages personnalisé:

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

Enregistrez le gestionnaire:

Dans le fichier Global.asax de la méthode Application_Start(), enregistrez votre gestionnaire en ajoutant le code ci-dessous.

GlobalConfiguration.Configuration.MessageHandlers.Add(new NullJsonHandler());

Maintenant, toute la réponse Asp.NET Web API qui contient null sera remplacée par un Json corps {} vide.

Références:

1.

2.

0
stom

Grâce à Darrel Miller, j'utilise pour l'instant cette solution.


WebApi utilise à nouveau StringContent "{}" dans certains environnements. Sérialiser par le biais de 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;
    }
}

Dérivé d'OkResult pour tirer parti d'Ok () dans 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
        };
    }
}

Remplacer Ok () dans ApiController

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