Web API 2: cách trả về JSON với tên thuộc tính camelCased, trên các đối tượng và đối tượng con của chúng


104

CẬP NHẬT

Cảm ơn tất cả các câu trả lời. Tôi đang thực hiện một dự án mới và có vẻ như cuối cùng tôi đã hiểu được điều này: Có vẻ như đoạn mã sau trên thực tế đã bị đổ lỗi:

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

nơi khác ...

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

Tôi đã bỏ qua JsonContent trông vô hại khi cho rằng đó là WebAPI nhưng không.

Cái này được sử dụng ở khắp mọi nơi ... Tôi có thể là người đầu tiên nói, wtf được không? Hoặc có lẽ đó phải là "Tại sao họ làm điều này?"


câu hỏi ban đầu theo sau

Người ta có thể nghĩ rằng đây sẽ là một cài đặt cấu hình đơn giản, nhưng nó đã bỏ qua tôi quá lâu rồi.

Tôi đã xem xét các giải pháp và câu trả lời khác nhau:

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

dường như không áp dụng cho phiên bản WebAPI mới nhất ...

Cách sau dường như không hoạt động - tên thuộc tính vẫn là PascalCased.

var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;

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

json.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); 

Câu trả lời của Mayank ở đây: Đối tượng phụ CamelCase JSON WebAPI (Đối tượng lồng nhau, đối tượng con) có vẻ như là một câu trả lời không thỏa đáng nhưng khả thi cho đến khi tôi nhận ra rằng các thuộc tính này sẽ phải được thêm vào mã được tạo vì chúng tôi đang sử dụng linq2sql ...

Bất kỳ cách nào để làm điều này tự động? Sự 'khó chịu' này đã làm tôi khó chịu trong một thời gian dài.



Ngoài ra, có một lý do tại sao Linq2SQL tạo ra các lớp một phần. Ngoài ra ... Linq2SQL WTF ?!
Aron

1
Cảm ơn nhưng liên kết này dành cho MVC, đó là API Web 2 mà tôi đang sử dụng và tôi không chắc liệu có cách nào để đặt loại nội dung như thế này và trả về một chuỗi hay không, nhưng nếu có thì có vẻ như không giống như giải pháp khá đúng .. Cảm ơn bạn cũng đã biết mẹo về các lớp một phần, nhưng liệu có thể thêm một thuộc tính vào thuộc tính được xác định trong phần khác của phần không?
Tom

Cũng có, linq2sql wtf ... không phải quyết định của tôi :)
Tom

kết quả là như nhau, sự khác biệt duy nhất là nơi bạn tiêm JsonSerializer. stackoverflow.com/questions/13274625/…
Aron

Câu trả lời:


175

Kết hợp tất cả lại với nhau, bạn sẽ ...

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

Chắc chắn là cách để bật nó lên, nhưng vấn đề của tôi là cài đặt này đang bị bỏ qua (xem câu trả lời của tôi)
Tom

1
@Tom ơ ... Tom có ​​biết gì json.UseDataContractJsonSerializer = true;không? Nó thông báo cho WebAPI không được sử dụng Json.Netđể tuần tự hóa. > _ <
Aron

Vâng, tôi làm ngay bây giờ. Tuy nhiên, cũng có một vấn đề bổ sung. Tôi đã xác minh điều này. Hãy xem câu trả lời của tôi. Cũng xem stackoverflow.com/questions/28552567/…
Tom

1
Trên thực tế, khi kiểm tra kỹ hơn, hóa ra tôi đã nhầm lẫn trong kết luận trước đó của mình. Xem bản cập nhật của tôi.
Tom

28

Đây là những gì làm việc cho tôi:

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

Và sau đó:

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

Các lớp CamelCasePropertyNamesContractResolverxuất phát từ Newtonsoft.Json.dlltrong Json.NET thư viện.


3
Cách tiếp cận này rất hữu ích khi người ta muốn chỉ có CamelCasing cho một số API, không phải cho tất cả các API trong ứng dụng. (Y)
droidbot

15

Nó chỉ ra rằng

return Json(result);

là thủ phạm, khiến quá trình tuần tự hóa bỏ qua cài đặt camelcase. Và đó

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

là droid tôi đang tìm kiếm.

Cũng thế

json.UseDataContractJsonSerializer = true;

Đang đặt một chiếc cờ lê trong công việc và hóa ra KHÔNG phải là chiếc droid mà tôi đang tìm kiếm.


Đây thực sự là câu trả lời sai. Xem cập nhật của tôi trong câu hỏi.
Tom

Tôi thực sự thấy đây là trường hợp. Khi quay lại Json(result), tôi thấy mọi thứ trong PascalCase, nhưng khi tôi quay lại, Content(StatusCode, result)nó hoạt động như mong đợi.
DeeKayy90

12

Tất cả các câu trả lời trên không phù hợp với tôi với Owin Hosting và Ninject. Đây là những gì đã làm việc cho tôi:

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

Sự khác biệt chính là: HttpConfiguration () mới thay vì GlobalConfiguration.Configuration.


Đối với tự lưu trữ thông qua OWIN, điều này là hoàn hảo. Cảm ơn!
Julian Melville

3
Nếu bạn đang sử dụng Owin, giải pháp này hoạt động hoàn hảo, nhưng chỉ sau khi bạn xé hết tóc ra!
Alastair

10

Mã của 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();

        }
    }


Đảm bảo rằng Phương thức hành động API của bạn trả về dữ liệu theo cách sau và bạn đã cài đặt phiên bản mới nhất của 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);
        }
    }

4

Trong Khởi động Owin của bạn, hãy thêm dòng này ...

 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

Đây là một điều khó hiểu, khi thuộc tính route không khớp với url GET nhưng url GET khớp với tên phương thức, thì lệnh jsonserializer camel case sẽ bị bỏ qua, ví dụ:

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

2

Tôi đã giải quyết nó theo những cách sau.

[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

Tôi đang sử dụng WebApi với Breeze và tôi gặp phải vấn đề tương tự khi cố gắng thực hiện một hành động không dễ dàng với bộ điều khiển dễ dàng. Tôi đã cố gắng sử dụng Request.GetConfiguration thẩm định nhưng kết quả tương tự. Vì vậy, khi tôi truy cập đối tượng được trả về bởi Request.GetConfiguration, tôi nhận ra rằng bộ tuần tự được sử dụng theo yêu cầu chính là bộ lưu trữ máy chủ dùng để biến nó trở nên kỳ diệu. Bằng mọi cách, tôi đã giải quyết được sự cố của mình khi tạo một HttpConfiguration khác:

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

và chuyển nó dưới dạng tham số tại Request.CreateResponse như sau:

return this.Request.CreateResponse(HttpStatusCode.OK, result, WebApiHelper.BreezeControllerCamelCase);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.