web-dev-qa-db-fra.com

Problème lié aux chameaux avec une API Web utilisant JSON.Net

Je souhaite renvoyer des données JSON contenant des boîtiers de chameaux à l'aide de l'API Web. J'ai hérité du fouillis d'un projet qui utilise tout le boîtier que le programmeur précédent avait envie d'utiliser pour le moment (sérieusement! Tout en majuscules, minuscules, Pascal-boîtiers et camel-douilles - faites votre choix!), Je ne peux donc pas utiliser le truc de mettre cela dans le fichier WebApiConfig.cs car cela cassera les appels d'API existants:

// Enforce camel-casing for the JSON objects being returned from API calls.
config.Formatters.OfType<JsonMediaTypeFormatter>().First().SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();

J'utilise donc une classe personnalisée qui utilise le sérialiseur JSON.Net. Voici le code:

using System.Web.Http;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;

public class JsonNetApiController : ApiController
{
    public string SerializeToJson(object objectToSerialize)
    {
        var settings = new JsonSerializerSettings
        {
            ContractResolver = new CamelCasePropertyNamesContractResolver()
        };

        if (objectToSerialize != null)
        {
            return JsonConvert.SerializeObject(objectToSerialize, Formatting.None, settings);
        }

        return string.Empty;
    }
}

Le problème est que les données brutes renvoyées ressemblent à ceci:

"[{\"average\":54,\"group\":\"P\",\"id\":1,\"name\":\"Accounting\"}]"

Comme vous pouvez le constater, les barres obliques inverses gâchent les choses. Voici comment j'appelle en utilisant la classe personnalisée:

public class Test
{
    public double Average { get; set; }
    public string Group { get; set; }
    public int Id { get; set; }
    public string Name { get; set; }
}

public class SomeController : JsonNetApiController
{
    public HttpResponseMessage Get()

    var responseMessage = new List<Test>
    {
        new Test
        {
            Id = 1,
            Name = "Accounting",
            Average = 54,
            Group = "P",
        }
    };

    return Request.CreateResponse(HttpStatusCode.OK, SerializeToJson(responseMessage), JsonMediaTypeFormatter.DefaultMediaType);

}

Que puis-je faire différemment pour me débarrasser des barres obliques inverses? Existe-t-il un moyen alternatif d’imposer le chameau?

14
Halcyon

Grâce à toutes les références à d'autres pages Stackoverflow, je vais publier trois solutions afin que toute autre personne ayant un problème similaire puisse choisir le code. Le premier exemple de code est celui que j'ai créé après avoir examiné ce que faisaient les autres. Les deux derniers proviennent d'autres utilisateurs de Stackoverflow. J'espère que ça aidera quelqu'un d'autre!

// Solution #1 - This is my solution. It updates the JsonMediaTypeFormatter whenever a response is sent to the API call.
// If you ever need to keep the controller methods untouched, this could be a solution for you.
using System;
using System.Net;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Web.Http;
using Newtonsoft.Json.Serialization;

public class CamelCasedApiController : ApiController
{
    public HttpResponseMessage CreateResponse(object responseMessageContent)
    {
        try
        {
            var httpResponseMessage = Request.CreateResponse(HttpStatusCode.OK, responseMessageContent, JsonMediaTypeFormatter.DefaultMediaType);
            var objectContent = httpResponseMessage.Content as ObjectContent;

            if (objectContent != null)
            {
                var jsonMediaTypeFormatter = new JsonMediaTypeFormatter
                {
                    SerializerSettings =
                    {
                        ContractResolver = new CamelCasePropertyNamesContractResolver()
                    }
                };

                httpResponseMessage.Content = new ObjectContent(objectContent.ObjectType, objectContent.Value, jsonMediaTypeFormatter);
            }

            return httpResponseMessage;
        }
        catch (Exception exception)
        {
            return Request.CreateResponse(HttpStatusCode.InternalServerError, exception.Message);
        }
    }
}

La deuxième solution utilise un attribut pour décorer la méthode du contrôleur API.

// http://stackoverflow.com/questions/14528779/use-camel-case-serialization-only-for-specific-actions
// This code allows the controller method to be decorated to use camel-casing. If you can modify the controller methods, use this approach.
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Web.Http.Filters;
using Newtonsoft.Json.Serialization;

public class CamelCasedApiMethodAttribute : ActionFilterAttribute
{
    private static JsonMediaTypeFormatter _camelCasingFormatter = new JsonMediaTypeFormatter();

    static CamelCasedApiMethodAttribute()
    {
        _camelCasingFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
    }

    public override void OnActionExecuted(HttpActionExecutedContext httpActionExecutedContext)
    {
        var objectContent = httpActionExecutedContext.Response.Content as ObjectContent;
        if (objectContent != null)
        {
            if (objectContent.Formatter is JsonMediaTypeFormatter)
            {
                httpActionExecutedContext.Response.Content = new ObjectContent(objectContent.ObjectType, objectContent.Value, _camelCasingFormatter);
            }
        }
    }
}

// Here is an example of how to use it.
[CamelCasedApiMethod]
public HttpResponseMessage Get()
{
    ...
}

La dernière solution utilise un attribut pour décorer tout le contrôleur API.

// http://stackoverflow.com/questions/19956838/force-camalcase-on-asp-net-webapi-per-controller
// This code allows the entire controller to be decorated to use camel-casing. If you can modify the entire controller, use this approach.
using System;
using System.Linq;
using System.Net.Http.Formatting;
using System.Web.Http.Controllers;
using Newtonsoft.Json.Serialization;

public class CamelCasedApiControllerAttribute : Attribute, IControllerConfiguration
{
    public void Initialize(HttpControllerSettings httpControllerSettings, HttpControllerDescriptor httpControllerDescriptor)
    {
        var jsonMediaTypeFormatter = httpControllerSettings.Formatters.OfType<JsonMediaTypeFormatter>().Single();
        httpControllerSettings.Formatters.Remove(jsonMediaTypeFormatter);

        jsonMediaTypeFormatter = new JsonMediaTypeFormatter
        {
            SerializerSettings =
            {
                ContractResolver = new CamelCasePropertyNamesContractResolver()
            }
        };

        httpControllerSettings.Formatters.Add(jsonMediaTypeFormatter);
    }
}

// Here is an example of how to use it.
[CamelCasedApiController]
public class SomeController : ApiController
{
    ...
}
18
Halcyon

Si vous souhaitez le définir globalement, vous pouvez simplement supprimer le formateur Json actuel de HttpConfiguration et le remplacer par le vôtre.

public static void Register(HttpConfiguration config)
{
    config.Formatters.Remove(config.Formatters.JsonFormatter);

    var serializer = new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() };
    var formatter = new JsonMediaTypeFormatter { Indent = true, SerializerSettings =  serializer };
    config.Formatters.Add(formatter);
}
1
Rikard

Commenter sur https://stackoverflow.com/a/26506573/887092 fonctionne dans certains cas mais pas dans d'autres

var jsonFormatter = GlobalConfiguration.Configuration.Formatters.JsonFormatter;

Cela fonctionne dans d'autres cas

var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();

Donc, couvrez toutes les bases avec:

    private void ConfigureWebApi(HttpConfiguration config)
    {
        //..

        foreach (var jsonFormatter in config.Formatters.OfType<JsonMediaTypeFormatter>())
        {
            jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
        }

        var singlejsonFormatter = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
        singlejsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();

    }
0
Todd