รับวัตถุแบบไดนามิกสำหรับ JsonConvert.DeserializeObject ที่ทำให้คุณสมบัติเป็นตัวพิมพ์ใหญ่

ฉันไม่แน่ใจว่าจะขอความช่วยเหลือได้อย่างไร และนี่เป็นเรื่องปกติที่ฉันเห็นด้วย ดังนั้นโปรดยกโทษให้ฉันด้วย ฉันจะพยายามอธิบายดังนี้:

• ฉันใช้ JSON โดยใช้ POST และรับออบเจ็กต์ไดนามิก ฉันต้องแปลงคุณสมบัติขาเข้าทั้งหมดในวัตถุไดนามิกเป็นตัวพิมพ์ใหญ่

• ฉันกำลังใช้สิ่งที่ฉันคิดว่าเป็นวิธีแก้ปัญหาที่หลบเลี่ยง ฉันกำลังแปลง JSON เป็นพจนานุกรมสตริง จากนั้นใส่ค่าลงในพจนานุกรมใหม่หลังจากแปลง Key เป็น Key.ToUpper() จากนั้นทำการดีซีเรียลไลซ์กลับเป็นวัตถุไดนามิก

โซลูชันที่ใช้งานได้ในปัจจุบันมีดังนี้:

string _StrJSON = @"{""FIELDA"" : ""1234"",""fieldb"" : ""OtherValue""}";

var d = JsonConvert.DeserializeObject<Dictionary<string, string>>(_StrJSON);

d.ContainsKey("FIELDB").Dump(); // returns false, obviously.

Dictionary<string, string> dr = new Dictionary<string, string>();

d.ToList().ForEach(r => dr.Add(r.Key.ToUpper(), r.Value));

dr.Dump("dr"); // FIELDA 1234  - FIELDB OtherValue 

var a  = JsonConvert.SerializeObject(dr);
a.Dump(); // {"FIELDA":"1234","FIELDB":"OtherValue"}

มันได้ผล

[แก้ไข] ความสับสนเกี่ยวกับ "var" ของฉันด้านบนและสิ่งอื่น ๆ ฉันชัดเจนมากว่าอะไรเป็นแบบไดนามิกและอะไรไม่ใช่ [/แก้ไข]

สิ่งที่ฉันได้ลองไปแล้วซึ่งใช้งานไม่ได้มีดังต่อไปนี้:

namespace Newtonsoft.Json
{
/// <summary>
/// Converts JSON keys to uppercase.
/// </summary>
public class UppercaseContractResolver : Serialization.DefaultContractResolver
{
    #region Methods.

    #region Public Methods.

    /// <summary>
    /// Resolves property name for this JSON object.
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    protected override string ResolvePropertyName(string key)
    {
        return key.ToUpper();
    }

    #endregion

    #endregion

    #region Constructors.

    /// <summary>
    /// Converts JSON keys to uppercase.
    /// </summary>
    public UppercaseContractResolver()
    {
    }

    #endregion
}

/// <summary>
/// Wrapper for Newtonsoft.Json.JsonConvert for JSON keys as uppercase.
/// </summary>
public static class JsonConvertUpper
{
    #region Members.        
    #endregion

    #region Methods.

    #region Public Methods.

    /// <summary>
    /// Tries to serialize specified object with JSON keys in upper case.
    /// <para>e.g. "key":value should become "KEY":value by using this method.</para>
    /// </summary>
    /// <param name="value">Object.</param>
    /// <returns></returns>
    public static string SerializeObjectUpper(object value)
    {
        return JsonConvert.SerializeObject(value, new JsonSerializerSettings
        {
            ContractResolver = new UppercaseContractResolver()
        });
    }

    /// <summary>
    /// Tries to Deserialize specified object with JSON keys in upper case.
    /// <para>e.g. "key":value should become "KEY":value by using this method.</para>
    /// </summary>
    /// <param name="strValue">String.</param>
    /// <returns></returns>
    public static object DeserializeObjectUpper(string strValue)
    {
        // DeserializeObject does not allow uppercase properties. So use SerializeObjectUpper and then deserialize.

        var value = JsonConvert.DeserializeObject(strValue);

        string strJSON = SerializeObjectUpper(value);

        return JsonConvert.DeserializeObject(strJSON, new JsonSerializerSettings()
        {
            ContractResolver = new UppercaseContractResolver()
        });
    }

    #endregion

    #endregion
}
}

วิธีการเรียกใช้ข้างต้นจะเป็น:

  dynamic json = JsonConvertUpper.DeserializeObjectUpper(_StrJSON);

                if (json.CTN== null)
                {...}

[แก้ไข] โปรดทราบว่าฉันไม่มีคลาสเนื่องจากคีย์ JSON จะต้องได้รับการปฏิบัติเหมือนเป็นตัวพิมพ์ใหญ่และคลาสและรหัสอื่น ๆ ฯลฯ ล้วนอยู่ใน ProperCase [/แก้ไข]

มีวิธีใดบ้างที่จะทำ ภายใน JsonConvert เลย? เพื่อหลีกเลี่ยงแพทช์แบบแมนนวลของฉัน? ความช่วยเหลือใด ๆ ที่ชื่นชม ขอบคุณ.


person Fawad Raza    schedule 03.03.2016    source แหล่งที่มา
comment
คุณสามารถเปลี่ยนชื่ออุปกรณ์ประกอบฉากโดยใช้แอตทริบิวต์ JsonProperty ในชั้นเรียนของคุณ   -  person Ňɏssa Pøngjǣrdenlarp    schedule 03.03.2016
comment
โปรดทราบว่าวัตถุไดนามิกคือวัตถุที่ได้รับการตัดสินใจในรันไทม์ สิ่งเหล่านี้ไม่ใช่ประเภทไดนามิก ตัวแปร var เป็นตัวแปรที่พิมพ์อย่างรุนแรง แค่อยากเคลียร์คำศัพท์นี้ที่นี่   -  person misha130    schedule 03.03.2016
comment
ใช่ฉันรู้ แต่ฉันได้แก้ไขคำถามของฉันแล้ว   -  person Fawad Raza    schedule 03.03.2016


คำตอบ (1)


เหตุผลที่ตัวแก้ไขสัญญาของคุณไม่ทำงานก็คือ ตัวแก้ไขสัญญา กำหนดวิธีการแมป JSON จากและไปยังคุณสมบัติของ POCO เมื่อทำการซีเรียลไลซ์ - แต่เมื่อคุณดีซีเรียลไลซ์เป็น dynamic Json.NET จะไม่ทำการแมปจากและไปยัง POCO จริง ๆ มันกำลังสร้าง JToken ลำดับชั้นโดยตรงจาก JSON ซึ่งเป็นสมาชิกที่ ใช้งาน IDynamicMetaObjectProvider เช่น.

dynamic o = JsonConvert.DeserializeObject(strJSON);

และ

dynamic o = JToken.Parse(strJSON);

เหมือนกัน.

เนื่องจากเป็นกรณีนี้ วิธีที่ง่ายที่สุดในการทำสิ่งที่คุณต้องการคือการแปลงชื่อคุณสมบัติแต่ละรายการให้เป็นตัวพิมพ์ใหญ่อย่างชัดเจนเมื่อมีการสร้างลำดับชั้น เช่น:

public static class JsonExtensions
{
    public static JToken ParseUppercase(string json)
    {
        using (var textReader = new StringReader(json))
        using (var jsonReader = new JsonTextReader(textReader))
        {
            return jsonReader.ParseUppercase();
        }
    }

    public static JToken ParseUppercase(this JsonReader reader)
    {
        return reader.Parse(n => n.ToUpperInvariant());
    }

    public static JToken Parse(this JsonReader reader, Func<string, string> nameMap)
    {
        JToken token;
        using (var writer = new RenamingJTokenWriter(nameMap))
        {
            writer.WriteToken(reader);
            token = writer.Token;
        }

        return token;
    }
}

class RenamingJTokenWriter : JTokenWriter
{
    readonly Func<string, string> nameMap;

    public RenamingJTokenWriter(Func<string, string> nameMap)
        : base()
    {
        if (nameMap == null)
            throw new ArgumentNullException();
        this.nameMap = nameMap;
    }

    public override void WritePropertyName(string name)
    {
        base.WritePropertyName(nameMap(name));
    }

    // No need to override WritePropertyName(string name, bool escape) since it calls WritePropertyName(string name)
}

แล้วใช้มันเหมือน:

dynamic json = JsonExtensions.ParseUppercase(_StrJSON);

ตัวอย่างซอ

person dbc    schedule 03.03.2016
comment
อ่า @dbc สวยงามจริงๆ! ขอบคุณมาก :) - person Fawad Raza; 04.03.2016
comment
เมื่อเช้านี้ฉันลองใช้ JToken และ JArray ด้วยลูปทุกประเภทสำหรับอาร์เรย์ภายในวัตถุ ฉันทดสอบซอด้วย string _StrJSON = @"{""FIELDA"" : ""1234"",""fieldb"" : ""OtherValue"", ""ARRAYDATA"": [ {""FIELD1"":""ArrayPropOne"", ""ArrayInsideArray1"": [ {""Fieldx"":""InsideArray1"", ""ArrayInsideArray2"": [ {""Fieldxy"":""InsideArray2""} ] } ]} ] }"; มันใช้งานได้ดี ขอบคุณมากสำหรับสิ่งนี้ ชื่นชมอย่างสูง - person Fawad Raza; 04.03.2016