Веб-API 2: як повернути JSON з іменами властивостей camelCased, на об'єкти та їх суб-об'єкти


104

ОНОВЛЕННЯ

Дякую за всі відповіді. Я над новим проектом, і, схоже, я нарешті дійшов до цього: Здається, винуватий був наступний код:

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

в іншому місці ...

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

Я не помітив нешкідливого вигляду JsonContent, припускаючи, що це WebAPI, але ні.

Це використовується скрізь ... Чи можу я просто першим сказати, wtf? Або, можливо, це має бути "Чому вони роблять це?"


випливає початкове запитання

Можна було б подумати, що це буде просте налаштування конфігурації, але це мені вже дуже довго ухиляється.

Я розглянув різні рішення та відповіді:

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

Схоже, не застосовується до останньої версії WebAPI ...

Наступне, здається, не працює - імена властивостей досі залишаються PascalCased.

var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;

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

json.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); 

Відповідь Майанка тут: Суб’єкти CamelCase JSON WebAPI (Вкладені об'єкти, дочірні об’єкти) здалися незадовільною, але працездатною відповіддю, поки я не зрозумів, що ці атрибути повинні бути додані до генерованого коду, як ми використовуємо linq2sql ...

Будь-який спосіб зробити це автоматично? Цей "бридкий" мучить мене вже давно.



Також є причина, чому Linq2SQL виробляє часткові класи. Також ... Linq2SQL WTF ?!
Арон

1
Дякую, але це посилання призначене для MVC, це Web API 2, який я використовую, і я не впевнений, чи є спосіб встановити тип вмісту, як цей, і повернути рядок, але якщо є, це не здається як цілком правильне рішення .. Дякую за пораду про часткові класи, але чи можна додати атрибут до властивості, визначеної в іншій частині часткового?
Том

Також так, linq2sql wtf ... не моє рішення :)
Том

результат той же, різниця лише в тому , де ви впорснути JsonSerializer. stackoverflow.com/questions/13274625/…
Арон

Відповіді:


175

Збираючи все це разом, ви отримуєте ...

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

Однозначно спосіб її ввімкнути, але моя проблема полягала в тому, що цей параметр був ігнорований (див. Мою відповідь)
Том,

1
@Tom erm ... Том ти знав, що json.UseDataContractJsonSerializer = true;робить? Це вказує WebAPI не використовувати Json.Netдля серіалізації. > _ <
Арон

Так, я зараз. Однак виникла і додаткова проблема. Я це перевірив. Дивіться мою відповідь. Також дивіться stackoverflow.com/questions/28552567/…
Том

1
Насправді при більш детальному огляді виявляється, що я помилився у своєму попередньому висновку. Дивіться моє оновлення.
Том

28

Це для мене працювало:

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

І потім:

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

Клас CamelCasePropertyNamesContractResolverприходить з Newtonsoft.Json.dllв Json.NET бібліотеці.


3
Такий підхід є дуже корисним, коли хочеться встановити камелю лише для деяких API, а не для всіх API в додатку. (Y)
droidbot

15

Виявляється, що

return Json(result);

Винуватець, змусивши процес серіалізації ігнорувати параметри верблюда. І це

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

був дроїд, якого я шукав.

Також

json.UseDataContractJsonSerializer = true;

Вкладав гайковий ключ у твори, і виявилося, що НЕ дроїд, якого я шукав.


Це насправді неправильна відповідь. Дивіться моє оновлення у питанні.
Том

Я фактично вважав, що це так. Повертаючись Json(result), я бачив усе в PascalCase, але коли повернувся, Content(StatusCode, result)він працював так, як очікувалося.
DeeKayy90

12

Усі вищезазначені відповіді не працювали для мене з Оуін-хостингом та Ninject. Ось що для мене спрацювало:

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

Ключова відмінність: нова HttpConfiguration (), а не GlobalConfiguration.Configuration.


Для самостійного хостингу через OWIN це ідеально. Дякую!
Джуліан Мелвілл

3
Якщо ви використовуєте Owin, це рішення працює чудово, але лише після того, як ви вирвете все волосся!
Аластер

10

Код 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();

        }
    }


Переконайтесь, що ваш метод дії API повертає дані наступним чином, і ви встановили останню версію встановленої Json.Net/Newtonsoft.Json:

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

4

У вашому запуску Owin додайте цей рядок ...

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

3

Ось незрозумілий, коли атрибут маршруту не збігався з URL-адресою GET, але URL-адреса GET відповідала імені методу, директива jsonserializer camel case буде ігноруватися, наприклад

http: // веб-сайт / 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();
}

2

Я вирішив це наступними способами.

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

0

Я використовую WebApi з Breeze, і я запустив ту саму проблему, коли намагався виконати дію без вітру в контролері вітру. Я спробував використовувати програму Request.GetConfiguration, але той самий результат. Отже, коли я отримую доступ до об'єкта, поверненого Request.GetConfiguration, я розумію, що серіалізатор, який використовується запитом, є тим, який сервер Breeze використовує, щоб зробити його магічним. У будь-якому випадку я вирішив свою проблему, створивши іншу HttpConfiguration:

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

і передаючи його як параметр на Request.CreateResponse, як описано нижче:

return this.Request.CreateResponse(HttpStatusCode.OK, result, WebApiHelper.BreezeControllerCamelCase);
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.