ฉันจะคืนค่า camelCase JSON ต่อเนื่องโดย JSON.NET จากวิธีการควบคุม ASP.NET MVC ได้อย่างไร


246

ปัญหาของฉันที่ฉันต้องการที่จะกลับ camelCased (เมื่อเทียบกับ PascalCase มาตรฐาน) JSON ข้อมูลผ่านActionResult s จากวิธีการควบคุม ASP.NET MVC, อันดับโดยJSON.NET

เป็นตัวอย่างให้พิจารณาคลาส C # ต่อไปนี้:

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

โดยค่าเริ่มต้นเมื่อส่งคืนอินสแตนซ์ของคลาสนี้จากตัวควบคุม MVC เป็น JSON มันจะถูกทำให้เป็นอนุกรมในแบบต่อไปนี้:

{
  "FirstName": "Joe",
  "LastName": "Public"
}

ฉันต้องการให้เป็นอนุกรม (โดย JSON.NET) เป็น:

{
  "firstName": "Joe",
  "lastName": "Public"
}

ฉันจะทำสิ่งนี้ได้อย่างไร

คำตอบ:


389

หรือใส่เพียง:

JsonConvert.SerializeObject(
    <YOUR OBJECT>, 
    new JsonSerializerSettings 
    { 
        ContractResolver = new CamelCasePropertyNamesContractResolver() 
    });

ตัวอย่างเช่น

return new ContentResult
{
    ContentType = "application/json",
    Content = JsonConvert.SerializeObject(new { content = result, rows = dto }, new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() }),
    ContentEncoding = Encoding.UTF8
};

2
สิ่งนี้มีความซับซ้อนมากขึ้นที่จะใช้เนื่องจากคุณต้องกำหนดค่า ContentResult สำหรับแต่ละวิธีการควบคุม
aknuds1

2
ใช่ฉันเข้าใจว่าคำตอบของคุณเป็นโซลูชันที่ใช้ซ้ำได้จุดของฉันคือทำให้ชัดเจนยิ่งขึ้นว่ามันเป็นเพียงพารามิเตอร์ในวิธีการ Serialize
WebDever

1
หากคุณส่งคืน JSON จากControllerวิธีการหนึ่งคุณอาจใช้คำสั่งApiControllerนี้ซึ่งในกรณีนี้คำตอบนี้ใช้ได้ดี
Simon Hartcher

1
@SimonHartcher พิจารณาขอบเขตของคำถามแม้ว่าไม่ใช่กรณีทั่วไป
aknuds1

1
ถูกต้องชนิดเนื้อหาสำหรับ JSON คือไม่application/json text/plain
Fred

94

ผมพบว่าเป็นทางออกที่ดีในการแก้ไขปัญหานี้บนเสื่อ Karlsson ของบล็อก วิธีแก้ปัญหาคือการเขียนคลาสย่อยของ ActionResult ที่จัดลำดับข้อมูลผ่าน JSON.NET โดยกำหนดค่าหลังเพื่อให้เป็นไปตามอนุสัญญา camelCase:

public class JsonCamelCaseResult : ActionResult
{
    public JsonCamelCaseResult(object data, JsonRequestBehavior jsonRequestBehavior)
    {
        Data = data;
        JsonRequestBehavior = jsonRequestBehavior;
    }

    public Encoding ContentEncoding { get; set; }

    public string ContentType { get; set; }

    public object Data { get; set; }

    public JsonRequestBehavior JsonRequestBehavior { get; set; }

    public override void ExecuteResult(ControllerContext context)
    {
        if (context == null)
        {
            throw new ArgumentNullException("context");
        }
        if (JsonRequestBehavior == JsonRequestBehavior.DenyGet && String.Equals(context.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))
        {
            throw new InvalidOperationException("This request has been blocked because sensitive information could be disclosed to third party web sites when this is used in a GET request. To allow GET requests, set JsonRequestBehavior to AllowGet.");
        }

        var response = context.HttpContext.Response;

        response.ContentType = !String.IsNullOrEmpty(ContentType) ? ContentType : "application/json";
        if (ContentEncoding != null)
        {
            response.ContentEncoding = ContentEncoding;
        }
        if (Data == null)
            return;

        var jsonSerializerSettings = new JsonSerializerSettings
        {
            ContractResolver = new CamelCasePropertyNamesContractResolver()
        };
        response.Write(JsonConvert.SerializeObject(Data, jsonSerializerSettings));
    }
}

จากนั้นใช้คลาสนี้ดังต่อไปนี้ในวิธีการควบคุม MVC ของคุณ:

public ActionResult GetPerson()
{
    return new JsonCamelCaseResult(new Person { FirstName = "Joe", LastName = "Public" }, JsonRequestBehavior.AllowGet)};
}

3
คำตอบที่สมบูรณ์แบบ: ทำความสะอาดและนำมาใช้ใหม่! ขอบคุณ.
ซานเดอ

1
ในขณะที่วิธีนี้ยังคงทำงานอยู่ แต่มันก็แนะนำ 4 ปีหลัง เรามีทางออกที่ดีกว่าไหม?
SharpCoder

59

สำหรับWebAPIให้ตรวจสอบลิงค์นี้: http://odetocode.com/blogs/scott/archive/2013/03/25/asp-net-webapi-tip-3-camelcasing-json.aspx

โดยทั่วไปเพิ่มรหัสนี้ของคุณApplication_Start:

var formatters = GlobalConfiguration.Configuration.Formatters;
var jsonFormatter = formatters.JsonFormatter;
var settings = jsonFormatter.SerializerSettings;
settings.ContractResolver = new CamelCasePropertyNamesContractResolver();

4
Web API และ MVC ได้รับการผสานใน ASP.NET 6
AlexFoxGill

1
ลิงค์เพื่อความสะดวก การตั้งค่านี้เล่นได้ดีมากกับคำตอบนี้: stackoverflow.com/a/26068063/398630 (คำถามที่แตกต่างกัน แต่ฉันใช้พวกเขาร่วมกันและลิงก์นี้อาจช่วยฉันและคนอื่น ๆ ในอนาคต)
BrainSlugs83

37

ฉันคิดว่านี่เป็นคำตอบง่ายๆที่คุณกำลังมองหา มาจากบล็อกของShawn Wildermuth :

// Add MVC services to the services container.
services.AddMvc()
  .AddJsonOptions(opts =>
  {
    opts.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
  });

2
ขอโทษนะฉัน ฉันอ่านโพสต์นี้เร็วเกินไป มันมีไว้สำหรับ ASP.NET 5
Quantium

8
กระแทกแดกดันฉันมาที่นี่เพื่อค้นหาคำตอบสำหรับคำถามที่คุณตอบมาที่นี่ดังนั้นแม้ว่าจะไม่ได้คำตอบสำหรับคำถามของ OP แต่มันก็ช่วยฉันได้ ขอบคุณ! :)
porcus

1
ฉันสองสิ่งที่ @porcus พูด! ขอบคุณ @Quantium!
Gromer

4
fyi สำหรับ ASP.NET Core 1.0 เป็นกรณีของอูฐโดยค่าเริ่มต้น OOTB
Chris Marisic

3
ปรากฎว่านี่ไม่ใช่ค่าเริ่มต้นสำหรับ. NET Core 1.0 หลังจากนั้นทั้งหมด วิธีนี้มีผลต่อคุณสมบัติแบบไดนามิกและสิ่งเหล่านั้นจะไม่ได้รับผลกระทบโดยค่าเริ่มต้น stackoverflow.com/questions/41329279/…
Niels Brinch

13

ทางเลือกอื่นสำหรับตัวกรองที่กำหนดเองคือการสร้างวิธีการขยายเพื่อจัดลำดับวัตถุใด ๆ ให้เป็น JSON

public static class ObjectExtensions
{
    /// <summary>Serializes the object to a JSON string.</summary>
    /// <returns>A JSON string representation of the object.</returns>
    public static string ToJson(this object value)
    {
        var settings = new JsonSerializerSettings
        {
            ContractResolver = new CamelCasePropertyNamesContractResolver(),
            Converters = new List<JsonConverter> { new StringEnumConverter() }
        };

        return JsonConvert.SerializeObject(value, settings);
    }
}

จากนั้นเรียกมันเมื่อกลับจากการทำงานของคอนโทรลเลอร์

return Content(person.ToJson(), "application/json");

สง่างามและเรียบง่าย
markau

1
คุณสามารถถ่ายโอนการตั้งค่าไปยังฟิลด์แบบอ่านอย่างเดียวแบบคงที่และเพิ่มวิธีการเสริม FromJson
ระเหยในตรอก

8

IMO ง่ายกว่าดีกว่า!

ทำไมคุณไม่ทำเช่นนี้?

public class CourseController : JsonController
{
    public ActionResult ManageCoursesModel()
    {
        return JsonContent(<somedata>);
    }
}

คอนโทรลเลอร์คลาสพื้นฐานอย่างง่าย

public class JsonController : BaseController
{
    protected ContentResult JsonContent(Object data)
    {
        return new ContentResult
        {
            ContentType = "application/json",
             Content = JsonConvert.SerializeObject(data, new JsonSerializerSettings { 
              ContractResolver = new CamelCasePropertyNamesContractResolver() }),
            ContentEncoding = Encoding.UTF8
        };
    }
}

7

ใน ASP.NET Core MVC

    public IActionResult Foo()
    {
        var data = GetData();

        var settings = new JsonSerializerSettings 
        { 
            ContractResolver = new CamelCasePropertyNamesContractResolver() 
        });

        return Json(data, settings);
    }

และยิ่งกว่านั้นให้ใส่ไว้ในไฟล์ Startup.cs
FatAlbert

6

ด้านล่างเป็นวิธีการดำเนินการที่ส่งกลับสตริง json (cameCase) โดยซีเรียลไลซ์อาร์เรย์ของวัตถุ

public string GetSerializedCourseVms()
    {
        var courses = new[]
        {
            new CourseVm{Number = "CREA101", Name = "Care of Magical Creatures", Instructor ="Rubeus Hagrid"},
            new CourseVm{Number = "DARK502", Name = "Defence against dark arts", Instructor ="Severus Snape"},
            new CourseVm{Number = "TRAN201", Name = "Transfiguration", Instructor ="Minerva McGonal"}
        };
        var camelCaseFormatter = new JsonSerializerSettings();
        camelCaseFormatter.ContractResolver = new CamelCasePropertyNamesContractResolver();
        return JsonConvert.SerializeObject(courses, camelCaseFormatter);
    }

หมายเหตุอินสแตนซ์ JsonSerializerSettings ส่งผ่านเป็นพารามิเตอร์ที่สอง นั่นคือสิ่งที่ทำให้ camelCase เกิดขึ้น


4

ฉันทำสิ่งนี้:

public static class JsonExtension
{
    public static string ToJson(this object value)
    {
        var settings = new JsonSerializerSettings
        {
            ContractResolver = new CamelCasePropertyNamesContractResolver(),
            NullValueHandling = NullValueHandling.Ignore,
            ReferenceLoopHandling = ReferenceLoopHandling.Serialize
        };
        return JsonConvert.SerializeObject(value, settings);
    }
}

นี่เป็นวิธีการขยายอย่างง่ายในแกน MVC มันจะให้ความสามารถในการ ToJson () กับทุกวัตถุในโครงการของคุณในความคิดของฉันในโครงการ MVC วัตถุส่วนใหญ่ควรมีความสามารถในการกลายเป็น json แน่นอนว่ามันขึ้นอยู่กับ :)


พิจารณาแยกตัวแปร "การตั้งค่า" นอกวิธี (เป็นฟิลด์คงที่ส่วนตัว "camelCaseSettings") เพื่อให้คุณไม่ได้เริ่มต้นตัวแปรใหม่ทุกครั้งที่มีการเรียกวิธี ToJson
Ekus

4

คุณต้องตั้งค่าในไฟล์ 'Startup.cs'

คุณต้องกำหนดในค่าเริ่มต้นของ JsonConvert นี่คือถ้าคุณต้องการใช้ไลบรารีในภายหลังเพื่อทำให้วัตถุเป็นอนุกรม

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
            .AddJsonOptions(options => {
                options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
                options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
            });
        JsonConvert.DefaultSettings = () => new JsonSerializerSettings
        {
            NullValueHandling = NullValueHandling.Ignore,
            ContractResolver = new CamelCasePropertyNamesContractResolver()
        };
    }

โปรดทราบว่าคำตอบนี้ถูกต้องสำหรับ ASP.NET Core แต่ไม่ใช่ ASP.NET (ซึ่งเป็นกรอบในคำถาม)
Nate Barbettini

0

หากคุณส่งคืน ActionResult ใน. net core web api หรือผลลัพธ์ IHttpAction คุณสามารถสรุปโมเดลของคุณด้วยวิธี Ok () ซึ่งจะจับคู่เคสบน front end ของคุณและทำให้มันเป็นอนุกรมสำหรับคุณ ไม่จำเป็นต้องใช้ JsonConvert :)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.