บังคับชื่อคุณสมบัติตัวพิมพ์เล็กจาก Json () ใน ASP.NET MVC


90

ให้ชั้นเรียนต่อไปนี้

public class Result
{      
    public bool Success { get; set; }

    public string Message { get; set; }
}

ฉันกำลังส่งคืนหนึ่งในสิ่งเหล่านี้ในการกระทำของคอนโทรลเลอร์

return Json(new Result() { Success = true, Message = "test"})

อย่างไรก็ตามกรอบงานฝั่งไคลเอ็นต์ของฉันคาดว่าคุณสมบัติเหล่านี้จะเป็นตัวพิมพ์เล็กและข้อความสำเร็จ โดยไม่ต้องมีชื่อคุณสมบัติตัวพิมพ์เล็กเป็นวิธีที่จะบรรลุความคิดนี้การเรียกฟังก์ชัน Json ปกติ

คำตอบ:


132

วิธีการเพื่อให้บรรลุนี้คือการดำเนินการที่กำหนดเองJsonResultเช่นที่นี่: การสร้างที่กำหนดเองและ ValueType serialising กับที่กำหนดเอง JsonResult (ลิงค์เดิมที่ตายแล้ว)

และใช้ serialiser ทางเลือกเช่นJSON.NETซึ่งสนับสนุนพฤติกรรมประเภทนี้เช่น:

Product product = new Product
{
  ExpiryDate = new DateTime(2010, 12, 20, 18, 1, 0, DateTimeKind.Utc),
  Name = "Widget",
  Price = 9.99m,
  Sizes = new[] {"Small", "Medium", "Large"}
};

string json = 
  JsonConvert.SerializeObject(
    product,
    Formatting.Indented,
    new JsonSerializerSettings 
    { 
      ContractResolver = new CamelCasePropertyNamesContractResolver() 
    }
);

ผลลัพธ์ใน

{
  "name": "Widget",
  "expiryDate": "\/Date(1292868060000)\/",
  "price": 9.99,
  "sizes": [
    "Small",
    "Medium",
    "Large"
  ]
}

1
ลิงค์นี้ใช้งานได้: james.newtonking.com/json/help/index.html?topic=html/…
Josef Engelfrost

หากคุณใช้ JSON.NET และไม่ต้องการ camelCase แต่เป็น snake_case ลองดูส่วนสำคัญนี้ช่วยฉันได้จริงๆ! gist.github.com/crallen/9238178
Niclas Lindqvist

ฉันจะ deserialize ได้อย่างไร? เช่น จาก "เล็ก" ถึง "เล็ก"
โกง

1
@NiclasLindqvist สำหรับเวอร์ชัน JSON.NET ที่ทันสมัยมีวิธีที่ง่ายกว่ามากในการรับ snake_case: newtonsoft.com/json/help/html/NamingStrategySnakeCase.htm
Søren Boisen

17

การเปลี่ยน serializer เป็นเรื่องง่ายหากคุณใช้ Web API แต่น่าเสียดายที่ MVC ใช้JavaScriptSerializerโดยไม่มีตัวเลือกในการเปลี่ยนสิ่งนี้เพื่อใช้ JSON.Net

คำตอบของ Jamesและคำตอบของ Danielทำให้ JSON.Net มีความยืดหยุ่น แต่หมายความว่าทุกที่ที่ปกติreturn Json(obj)คุณจะต้องเปลี่ยนreturn new JsonNetResult(obj)หรือคล้ายกันซึ่งหากคุณมีโปรเจ็กต์ขนาดใหญ่สามารถพิสูจน์ปัญหาได้และยังไม่ยืดหยุ่นมากหาก คุณเปลี่ยนใจกับ Serializer ที่คุณต้องการใช้


ฉันตัดสินใจไปตามActionFilterเส้นทางแล้ว โค้ดด้านล่างช่วยให้คุณดำเนินการใด ๆ โดยใช้JsonResultและใช้แอตทริบิวต์เพื่อใช้ JSON.Net (พร้อมคุณสมบัติตัวพิมพ์เล็ก):

[JsonNetFilter]
[HttpPost]
public ActionResult SomeJson()
{
    return Json(new { Hello = "world" });
}

// outputs: { "hello": "world" }

คุณยังสามารถตั้งค่านี้ให้ใช้กับการกระทำทั้งหมดโดยอัตโนมัติได้ด้วย (ด้วยการisตรวจสอบประสิทธิภาพเล็กน้อยเท่านั้น):

FilterConfig.cs

// ...
filters.Add(new JsonNetFilterAttribute());

รหัส

public class JsonNetFilterAttribute : ActionFilterAttribute
{
    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        if (filterContext.Result is JsonResult == false)
            return;

        filterContext.Result = new CustomJsonResult((JsonResult)filterContext.Result);
    }

    private class CustomJsonResult : JsonResult
    {
        public CustomJsonResult(JsonResult jsonResult)
        {
            this.ContentEncoding = jsonResult.ContentEncoding;
            this.ContentType = jsonResult.ContentType;
            this.Data = jsonResult.Data;
            this.JsonRequestBehavior = jsonResult.JsonRequestBehavior;
            this.MaxJsonLength = jsonResult.MaxJsonLength;
            this.RecursionLimit = jsonResult.RecursionLimit;
        }

        public override void ExecuteResult(ControllerContext context)
        {
            if (context == null)
                throw new ArgumentNullException("context");

            if (this.JsonRequestBehavior == JsonRequestBehavior.DenyGet
                && String.Equals(context.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))
                throw new InvalidOperationException("GET not allowed! Change JsonRequestBehavior to AllowGet.");

            var response = context.HttpContext.Response;

            response.ContentType = String.IsNullOrEmpty(this.ContentType) ? "application/json" : this.ContentType;

            if (this.ContentEncoding != null)
                response.ContentEncoding = this.ContentEncoding;

            if (this.Data != null)
            {
                var json = JsonConvert.SerializeObject(
                    this.Data,
                    new JsonSerializerSettings
                        {
                            ContractResolver = new CamelCasePropertyNamesContractResolver()
                        });

                response.Write(json);
            }
        }
    }
}

10

ด้วยโซลูชันของฉันคุณสามารถเปลี่ยนชื่อสถานที่ให้บริการทุกแห่งที่คุณต้องการได้

ฉันพบส่วนหนึ่งของการแก้ปัญหาที่นี่และใน SO

public class JsonNetResult : ActionResult
    {
        public Encoding ContentEncoding { get; set; }
        public string ContentType { get; set; }
        public object Data { get; set; }

        public JsonSerializerSettings SerializerSettings { get; set; }
        public Formatting Formatting { get; set; }

        public JsonNetResult(object data, Formatting formatting)
            : this(data)
        {
            Formatting = formatting;
        }

        public JsonNetResult(object data):this()
        {
            Data = data;
        }

        public JsonNetResult()
        {
            Formatting = Formatting.None;
            SerializerSettings = new JsonSerializerSettings();
        }

        public override void ExecuteResult(ControllerContext context)
        {
            if (context == null)
                throw new ArgumentNullException("context");
            var response = context.HttpContext.Response;
            response.ContentType = !string.IsNullOrEmpty(ContentType)
              ? ContentType
              : "application/json";
            if (ContentEncoding != null)
                response.ContentEncoding = ContentEncoding;

            if (Data == null) return;

            var writer = new JsonTextWriter(response.Output) { Formatting = Formatting };
            var serializer = JsonSerializer.Create(SerializerSettings);
            serializer.Serialize(writer, Data);
            writer.Flush();
        }
    }

ดังนั้นในคอนโทรลเลอร์ของฉันฉันสามารถทำได้

        return new JsonNetResult(result);

ในโมเดลของฉันตอนนี้ฉันสามารถมี:

    [JsonProperty(PropertyName = "n")]
    public string Name { get; set; }

โปรดทราบว่าตอนนี้คุณต้องตั้งค่าเป็นJsonPropertyAttributeทุกคุณสมบัติที่คุณต้องการทำให้เป็นอนุกรม


1

แม้ว่าจะเป็นคำถามเก่า แต่หวังว่าด้านล่างข้อมูลโค้ดจะเป็นประโยชน์กับผู้อื่น

ฉันทำด้านล่างด้วย MVC5 Web API

public JsonResult<Response> Post(Request request)
    {
        var response = new Response();

        //YOUR LOGIC IN THE METHOD
        //.......
        //.......

        return Json<Response>(response, new JsonSerializerSettings() { ContractResolver = new CamelCasePropertyNamesContractResolver() });
    }

0

คุณสามารถเพิ่มการตั้งค่านี้Global.asaxและจะใช้งานได้ทุกที่

public class Global : HttpApplication
{   
    void Application_Start(object sender, EventArgs e)
    {
        //....
         JsonConvert.DefaultSettings = () =>
         {
             var settings = new JsonSerializerSettings
             {
                 ContractResolver = new CamelCasePropertyNamesContractResolver(),
                 PreserveReferencesHandling = PreserveReferencesHandling.None,
                 Formatting = Formatting.None
             };

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