web-dev-qa-db-fra.com

Web API 2: comment renvoyer JSON avec les noms de propriété camelCased, sur les objets et leurs sous-objets

UPDATE

Merci pour toutes les réponses. Je suis sur un nouveau projet et on dirait que j'ai enfin compris: il semble que le code suivant soit en fait à blâmer:

public static HttpResponseMessage GetHttpSuccessResponse(object response, HttpStatusCode code = HttpStatusCode.OK)
{
    return new HttpResponseMessage()
    {
        StatusCode = code,
        Content = response != null ? new JsonContent(response) : null
    };
}

autre part...

public JsonContent(object obj)
{
    var encoded = JsonConvert.SerializeObject(obj, Newtonsoft.Json.Formatting.None, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore } );
    _value = JObject.Parse(encoded);

    Headers.ContentType = new MediaTypeHeaderValue("application/json");
}

J'avais négligé l'innocent JsonContent en supposant que c'était WebAPI, mais non.

Ceci est utilisé partout ... Puis-je juste être le premier à dire, wtf? Ou peut-être que cela devrait être "Pourquoi font-ils cela?"


la question initiale suit

On aurait pu penser que ce serait un simple paramètre de configuration, mais cela m’échappe depuis trop longtemps.

J'ai examiné diverses solutions et réponses:

https://Gist.github.com/rdingwall/2012642

ne semble pas s'appliquer à la dernière version de WebAPI ...

Ce qui suit ne semble pas fonctionner - les noms de propriété sont toujours PascalCased.

var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;

json.UseDataContractJsonSerializer = true;
json.SerializerSettings.NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore;

json.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); 

La réponse de Mayank ici: sous-objets CamelCase JSON WebAPI (objets imbriqués, objets enfants) semblait être une réponse peu satisfaisante mais pratique jusqu'à ce que je sache que ces attributs devraient être ajoutés au code généré car nous utilisons linq2sql. ..

Tout moyen de le faire automatiquement? Ce "méchant" me tourmente depuis longtemps maintenant.

93
Tom

En réunissant tout cela, vous obtenez ...

protected void Application_Start()
{
    HttpConfiguration config = GlobalConfiguration.Configuration;
    config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
    config.Formatters.JsonFormatter.UseDataContractJsonSerializer = false;
}
163
Aron

C'est ce qui a fonctionné pour moi:

internal static class ViewHelpers
{
    public static JsonSerializerSettings CamelCase
    {
        get
        {
            return new JsonSerializerSettings {
                ContractResolver = new CamelCasePropertyNamesContractResolver()
            };
        }
    }
}

Puis:

[HttpGet]
[Route("api/campaign/list")]
public IHttpActionResult ListExistingCampaigns()
{
    var domainResults = _campaignService.ListExistingCampaigns();
    return Json(domainResults, ViewHelpers.CamelCase);
}

La classe CamelCasePropertyNamesContractResolver provient de la bibliothèque Newtonsoft.Json.dll in Json.NET .

26
felix-b

Il se trouve que

return Json(result);

était à l'origine du processus de sérialisation et ignorait le paramètre camelcase. Et cela

return Request.CreateResponse(HttpStatusCode.OK, result, Request.GetConfiguration());

était le droïde que je cherchais.

Aussi

json.UseDataContractJsonSerializer = true;

Était en train de mettre une clé dans les travaux et s'est avéré être pas le droïde que je cherchais.

12
Tom

Toutes les réponses ci-dessus n'ont pas fonctionné pour moi avec Owin Hosting et Ninject. Voici ce qui a fonctionné pour moi:

public partial class Startup
{
    public void Configuration(IAppBuilder app)
    {
        // Get the ninject kernel from our IoC.
        var kernel = IoC.GetKernel();

        var config = new HttpConfiguration();

        // More config settings and OWIN middleware goes here.

        // Configure camel case json results.
        ConfigureCamelCase(config);

        // Use ninject middleware.
        app.UseNinjectMiddleware(() => kernel);

        // Use ninject web api.
        app.UseNinjectWebApi(config);
    }

    /// <summary>
    /// Configure all JSON responses to have camel case property names.
    /// </summary>
    private void ConfigureCamelCase(HttpConfiguration config)
    {
        var jsonFormatter = config.Formatters.JsonFormatter;
        // This next line is not required for it to work, but here for completeness - ignore data contracts.
        jsonFormatter.UseDataContractJsonSerializer = false;
        var settings = jsonFormatter.SerializerSettings;
#if DEBUG
        // Pretty json for developers.
        settings.Formatting = Formatting.Indented;
#else
        settings.Formatting = Formatting.None;
#endif
        settings.ContractResolver = new CamelCasePropertyNamesContractResolver();
    }
}

La principale différence est la suivante: new HttpConfiguration () plutôt que GlobalConfiguration.Configuration.

12
mkaj

Code de WebApiConfig:

    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API configuration and services

            // Web API routes
            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );

            //This line sets json serializer's ContractResolver to CamelCasePropertyNamesContractResolver, 
            //  so API will return json using camel case
            config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();

        }
    }


Assurez-vous que votre méthode d’action API renvoie les données de la manière suivante et que vous avez installé la dernière version de Json.Net/Newtonsoft.Json. Installé:

    [HttpGet]
    public HttpResponseMessage List()
    {
        try
        {
            var result = /*write code to fetch your result*/;
            return Request.CreateResponse(HttpStatusCode.OK, cruises);
        }
        catch (Exception ex)
        {
            return Request.CreateResponse(HttpStatusCode.InternalServerError, ex.Message);
        }
    }
9
Jay Shah

Dans votre startup Owin, ajoutez cette ligne ...

 public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        var webApiConfiguration = ConfigureWebApi();            
        app.UseWebApi(webApiConfiguration);
    }

    private HttpConfiguration ConfigureWebApi()
    {
        var config = new HttpConfiguration();

        // ADD THIS LINE HERE AND DONE
        config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); 

        config.MapHttpAttributeRoutes();
        return config;
    }
}
4
smatthews1999

En voici une obscure: lorsque la valeur de l'attribut route ne correspond pas à celle de l'URL GET mais que celle-ci correspond au nom de la méthode, la directive relative à la casse des chameaux de jsonserializer est ignorée, par exemple.

http: // site web/api/geo/geodata

//uppercase fail cakes
[HttpGet]
[Route("countries")]
public async Task<GeoData> GeoData()
{
    return await geoService.GetGeoData();
}

//lowercase nomnomnom cakes
[HttpGet]
[Route("geodata")]
public async Task<GeoData> GeoData()
{
    return await geoService.GetGeoData();
}
3
jenson-button-event

Je l'ai résolu de la manière suivante.

[AllowAnonymous]
[HttpGet()]
public HttpResponseMessage GetAllItems(int moduleId)
{
    HttpConfiguration config = new HttpConfiguration();
            config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
            config.Formatters.JsonFormatter.UseDataContractJsonSerializer = false;

            try
            {
                List<ItemInfo> itemList = GetItemsFromDatabase(moduleId);
                return Request.CreateResponse(HttpStatusCode.OK, itemList, config);
            }
            catch (System.Exception ex)
            {
                return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, ex.Message);
            }
}
1
Khademul Basher

J'utilise WebAPI avec Breeze et je courais le même problème lorsque vous essayez d'exécuter une action non-brise dans un contrôleur de jeu d'enfant. J'ai essayé d'utiliser le Request Request.GetConfiguration apprach mais le même résultat. Donc, quand j'accéder à l'objet retourné par Request.GetConfiguration Je me rends compte que le sérialiseur utilisé par demande est celle que l'utilisation brise-serveur pour le faire est magique. Quoi qu'il en soit, j'ai résolu mon problème en créant une configuration HttpConfiguration différente:

public static HttpConfiguration BreezeControllerCamelCase
        {
            get
            {
                var config = new HttpConfiguration();
                var jsonSerializerSettings = config.Formatters.JsonFormatter.SerializerSettings;
                jsonSerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
                jsonSerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
                config.Formatters.JsonFormatter.UseDataContractJsonSerializer = false;

                return config;
            }
        }

et en le passant comme paramètre à Request.CreateResponse comme suit:

return this.Request.CreateResponse(HttpStatusCode.OK, result, WebApiHelper.BreezeControllerCamelCase);
0