Web API 2: как вернуть JSON с именами свойств camelCased, на объекты и их под-объекты

UPDATE

Спасибо за все ответы. Я нахожусь в новом проекте, и похоже, что я, наконец, дошел до конца: похоже, что на самом деле виноват следующий код:

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

Mayank ответьте здесь: Субъекты CamelCase JSON WebAPI (вложенные объекты, дочерние объекты) выглядели как неудовлетворительный, но работоспособный ответ, пока я не понял, что эти атрибуты должны быть добавлен в сгенерированный код, поскольку мы используем linq2sql...

Любой способ сделать это автоматически? Эта "противная" меня мучила уже давно.

Ответ 1

Положив все это вместе, вы получите...

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

Ответ 2

Это то, что сработало для меня:

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

Все приведенные выше ответы не помогли мне с Owin Hosting и 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.

Ответ 4

Оказывается, что

return Json(result);

был виновником, в результате чего процесс сериализации игнорировал настройку камеры. И что

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

был дроидом, которого я искал.

Также

json.UseDataContractJsonSerializer = true;

Вложил гаечный ключ в свои работы и оказался НЕ дроидом, которого я искал.

Ответ 5

Код 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 ContractResolver to CamelCasePropertyNamesContractResolver, 
            //  so API will return json using camel case
            config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();

        }
    }


Убедитесь, что ваш API Action Method возвращает данные следующим образом, и вы установили последнюю версию Json.Net/Newtonsoft.Json Installed:

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

Ответ 6

В вашей Owin Startup добавьте эту строку...

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

Ответ 7

Здесь неясный, когда атрибут маршрута не соответствует URL-адресу GET, но URL-адрес GET соответствует имени метода, директива case jsonserializer camel будет игнорироваться, например.

http://website/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();
}

Ответ 8

Я решил это следующими способами.

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

Ответ 9

Я использую WebApi с Breeze, и я запускал ту же самую проблему при попытке выполнить не-бризовое действие в контроллере Breeze. Я попытался использовать оценку Request.GetConfiguration, но тот же результат. Таким образом, когда я обращаюсь к объекту, возвращаемому Request.GetConfiguration, я понимаю, что сериализатор, используемый по запросу, является тем, который используется сервером breeze-server, чтобы сделать его магическим. В любом случае, я решил проблему, создав другую 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);