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

คำตอบของ Mayank ที่นี่: CamelCase JSON WebAPI Sub-Objects (วัตถุที่ซ้อนกันออบเจ็กต์ลูก)ดูเหมือนจะเป็นคำตอบที่ไม่น่าพอใจ แต่ใช้งานได้จนกว่าฉันจะรู้ว่าจะต้องเพิ่มแอตทริบิวต์เหล่านี้ในโค้ดที่สร้างขึ้นเนื่องจากเราใช้ linq2sql ...

วิธีใดในการดำเนินการนี้โดยอัตโนมัติ 'น่ารังเกียจ' นี้รบกวนฉันมานานแล้ว



นอกจากนี้ยังมีเหตุผลว่าทำไม Linq2SQL จึงสร้างคลาสบางส่วน นอกจากนี้ ... Linq2SQL WTF ?!
Aron

1
ขอบคุณ แต่ลิงค์นี้มีไว้สำหรับ MVC เป็น Web API 2 ที่ฉันใช้อยู่และฉันไม่แน่ใจว่ามีวิธีตั้งค่าประเภทเนื้อหาแบบนี้หรือไม่และส่งคืนสตริง แต่ถ้าไม่มีดูเหมือนว่า เหมือนวิธีแก้ปัญหาที่ถูกต้อง .. ขอบคุณสำหรับเคล็ดลับเกี่ยวกับคลาสบางส่วนด้วย แต่จะเพิ่มแอตทริบิวต์ให้กับคุณสมบัติที่กำหนดไว้ในส่วนอื่น ๆ ของบางส่วนได้หรือไม่?
ทอม

ใช่ linq2sql wtf ... ไม่ใช่การตัดสินใจของฉัน :)
ทอม

JsonSerializerผลที่ได้คือเดียวกันที่แตกต่างเป็นที่ที่คุณฉีด stackoverflow.com/questions/13274625/…
Aron

คำตอบ:


175

รวมทั้งหมดเข้าด้วยกันคุณจะได้รับ ...

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

แน่นอนวิธีเปิดใช้งาน แต่ปัญหาของฉันคือการตั้งค่านี้ถูกเพิกเฉย (ดูคำตอบของฉัน)
ทอม

1
@ ทอมเอิ่ม ... ทอมรู้อะไรjson.UseDataContractJsonSerializer = true;ไหม? มันบอกไม่ให้ WebAPI ใช้Json.Netสำหรับการทำให้เป็นอนุกรม > _ <
Aron

ใช่ฉันทำตอนนี้ อย่างไรก็ตามยังมีปัญหาเพิ่มเติม ฉันยืนยันสิ่งนี้แล้ว ดูคำตอบของฉัน ดู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
วิธีนี้มีประโยชน์มากเมื่อต้องการมี camelCasing สำหรับ 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

คำตอบทั้งหมดข้างต้นไม่ได้ผลสำหรับฉันกับ 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


สำหรับการโฮสต์ด้วยตนเองผ่าน OWIN นี่เหมาะมาก ขอบคุณ!
Julian Melville

3
หากคุณใช้ Owin วิธีนี้จะใช้ได้ผลดี แต่หลังจากที่คุณฉีกผมจนหมดแล้ว!
Alastair

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 Action Method ของคุณส่งคืนข้อมูลด้วยวิธีต่อไปนี้และคุณได้ติดตั้ง 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 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;
    }
}

3

นี่คือสิ่งที่ไม่ชัดเจนเมื่อแอตทริบิวต์เส้นทางไม่ตรงกับ GET url แต่ GET url ตรงกับชื่อวิธีการคำสั่งกรณีอูฐ jsonserializer จะถูกละเว้นเช่น

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 และฉันพบปัญหาเดียวกันเมื่อพยายามเรียกใช้แอคชั่นที่ไม่ใช่ breeze ในตัวควบคุม breeze ฉันพยายามใช้การร้องขอการประเมิน GetConfiguration แต่ผลลัพธ์เดียวกัน ดังนั้นเมื่อฉันเข้าถึงวัตถุที่ส่งคืนโดย Request.GetConfiguration ฉันตระหนักดีว่า serializer ที่ใช้ตามคำขอเป็นสิ่งที่เซิร์ฟเวอร์ 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);
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.