API Web 2: cara mengembalikan JSON dengan nama properti camelCased, pada objek dan sub-objeknya

104

MEMPERBARUI

Terima kasih atas semua jawabannya. Saya sedang dalam proyek baru dan sepertinya saya akhirnya sampai di dasar ini: Sepertinya kode berikut sebenarnya yang harus disalahkan:

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

di tempat lain...

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

Saya telah mengabaikan JsonContent yang tampak tidak berbahaya dengan asumsi itu adalah WebAPI tetapi tidak.

Ini digunakan di mana-mana ... Bisakah saya menjadi yang pertama mengatakan, wtf? Atau mungkin itu seharusnya menjadi "Mengapa mereka melakukan ini?"


pertanyaan asli berikut

Orang akan mengira ini akan menjadi pengaturan konfigurasi sederhana, tetapi itu terlalu lama untuk saya sekarang.

Saya telah melihat berbagai solusi dan jawaban:

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

tampaknya tidak berlaku untuk versi WebAPI terbaru ...

Berikut ini tampaknya tidak berhasil - nama properti masih PascalCased.

var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;

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

json.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); 

Jawaban Mayank di sini: Sub-Objek CamelCase JSON WebAPI (Objek bersarang, objek anak) tampak seperti jawaban yang tidak memuaskan tetapi bisa diterapkan sampai saya menyadari atribut ini harus ditambahkan ke kode yang dihasilkan karena kami menggunakan linq2sql ...

Adakah cara untuk melakukan ini secara otomatis? 'Jahat' ini telah mengganggu saya sejak lama.

Tom
sumber
Juga ada alasan mengapa Linq2SQL menghasilkan kelas parsial. Juga ... Linq2SQL WTF ?!
Aron
1
Terima kasih, tetapi tautan ini untuk MVC, ini adalah API Web 2 yang saya gunakan, dan saya tidak yakin apakah ada cara untuk menyetel tipe konten seperti ini, dan mengembalikan string, tetapi jika ada, sepertinya tidak menyukai solusi yang cukup tepat .. Terima kasih atas tip tentang kelas parsial juga, tetapi apakah mungkin untuk menambahkan atribut ke properti yang ditentukan di bagian lain parsial?
Tom
Juga ya, linq2sql wtf ... bukan keputusan saya :)
Tom
hasilnya sama, satu-satunya perbedaan adalah tempat Anda menyuntikkan JsonSerializer. stackoverflow.com/questions/13274625/…
Aron

Jawaban:

175

Menyatukan semuanya, Anda mendapatkan ...

protected void Application_Start()
{
    HttpConfiguration config = GlobalConfiguration.Configuration;
    config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
    config.Formatters.JsonFormatter.UseDataContractJsonSerializer = false;
}
Aron
sumber
Jelas cara untuk menyalakannya, tetapi masalah saya adalah bahwa pengaturan ini diabaikan (lihat jawaban saya)
Tom
1
@Tom erm ... Tom, tahukah kamu apa json.UseDataContractJsonSerializer = true;? Ini memberitahu WebAPI untuk tidak digunakan Json.Netuntuk serialisasi. > _ <
Aron
Ya, saya lakukan sekarang. Namun, ada juga masalah tambahan. Saya memverifikasi ini. Lihat jawaban saya. Juga lihat stackoverflow.com/questions/28552567/…
Tom
1
Ternyata, jika diteliti lebih dekat, ternyata saya salah kaprah dalam kesimpulan saya sebelumnya. Lihat pembaruan saya.
Tom
28

Inilah yang berhasil untuk saya:

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

Lalu:

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

Kelas CamelCasePropertyNamesContractResolverberasal dari Newtonsoft.Json.dlldalam Json.NET perpustakaan.

felix-b
sumber
3
Pendekatan ini sangat berguna ketika seseorang ingin memiliki camelCasing hanya untuk beberapa API, bukan untuk semua API dalam aplikasi. (Y)
droidbot
15

Ternyata itu

return Json(result);

adalah pelakunya, menyebabkan proses serialisasi mengabaikan pengaturan camelcase. Dan itu

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

adalah droid yang saya cari.

Juga

json.UseDataContractJsonSerializer = true;

Sedang memasang kunci pas dan ternyata BUKAN droid yang saya cari.

Tom
sumber
Ini sebenarnya jawaban yang salah. Lihat pembaruan saya di pertanyaan.
Tom
Saya benar-benar menemukan ini menjadi masalahnya. Ketika kembali Json(result), saya melihat semuanya di PascalCase, tetapi ketika saya kembali, Content(StatusCode, result)itu berfungsi seperti yang diharapkan.
DeeKayy90
12

Semua jawaban di atas tidak berhasil untuk saya dengan Owin Hosting dan Ninject. Inilah yang berhasil untuk saya:

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

Perbedaan utamanya adalah: HttpConfiguration () baru daripada GlobalConfiguration.Configuration.

mkaj
sumber
Untuk hosting mandiri melalui OWIN, ini sempurna. Terima kasih!
Julian Melville
3
Jika Anda menggunakan Owin, solusi ini bekerja dengan sempurna, tetapi hanya setelah Anda merobek semua rambut Anda!
Alastair
10

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

        }
    }


Pastikan Metode Tindakan API Anda mengembalikan data dengan cara berikut dan Anda telah menginstal versi terbaru Json.Net/Newtonsoft.Json Terinstal:

    [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);
        }
    }
Jay Shah
sumber
4

Di Startup Owin Anda, tambahkan baris ini ...

 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;
    }
}
smatthews1999
sumber
3

Berikut ini salah satu yang tidak jelas, ketika atribut rute tidak cocok dengan url GET tetapi url GET cocok dengan nama metode, perintah kasus unta jsonserializer akan diabaikan misalnya

http: // situs 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();
}
jenson-button-event
sumber
2

Saya telah menyelesaikannya dengan cara berikut.

[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);
            }
}
Khademul Basher
sumber
0

Saya menggunakan WebApi dengan Breeze dan saya mengalami masalah yang sama saat mencoba menjalankan tindakan non-angin ke pengontrol angin. Saya mencoba menggunakan Apprach Request.GetConfiguration tetapi hasilnya sama. Jadi, ketika saya mengakses objek yang dikembalikan oleh Request.GetConfiguration, saya menyadari bahwa serializer yang digunakan oleh permintaan adalah salah satu yang digunakan oleh server angin untuk membuatnya ajaib. Bagaimanapun, saya menyelesaikan masalah saya dengan membuat HttpConfiguration yang berbeda:

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

dan meneruskannya sebagai parameter di Request.CreateResponse sebagai berikut:

return this.Request.CreateResponse(HttpStatusCode.OK, result, WebApiHelper.BreezeControllerCamelCase);
Leonardo Neninger
sumber