【问题标题】:Get a dynamic object for JsonConvert.DeserializeObject making properties uppercase获取 JsonConvert.DeserializeObject 的动态对象,使属性大写
【发布时间】:2016-03-04 18:16:17
【问题描述】:

我不知道如何寻求帮助,我同意这有点不寻常,所以请原谅我。我将尝试解释如下:

• 我正在使用 POST 使用 JSON 并获取一个动态对象。我需要将动态对象中的所有传入属性都转换为大写。

• 我正在使用 我认为 是一个可靠的解决方案。我将 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 有什么办法吗?为了避免我的手动补丁?任何帮助表示赞赏。谢谢。

【问题讨论】:

  • 您可以使用类的JsonProperty 属性重命名道具
  • 请注意,动态对象是在运行时决定的。这些不是动态类型。 “var”变量是强类型变量。只是想在这里清除这个术语
  • 是的,我知道,但我已经编辑了我的问题。

标签: c# json json.net


【解决方案1】:

您的合同解析器不起作用的原因是 Json.NET 的 contract resolver 定义了在序列化时如何将 JSON 从和映射到 POCO 的属性——但是当您反序列化到 dynamic 时,Json.NET 是它实际上并没有从 POCO 映射到 POCO,而是直接从 JSON 构建 JToken 层次结构,其中的成员 implement 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);

示例fiddle

【讨论】:

  • 啊@dbc 绝对漂亮! 非常感谢。 :)
  • 今天早上我尝试使用 JToken 和 JArray 进行各种循环,用于对象内部的数组。我用string _StrJSON = @"{""FIELDA"" : ""1234"",""fieldb"" : ""OtherValue"", ""ARRAYDATA"": [ {""FIELD1"":""ArrayPropOne"", ""ArrayInsideArray1"": [ {""Fieldx"":""InsideArray1"", ""ArrayInsideArray2"": [ {""Fieldxy"":""InsideArray2""} ] } ]} ] }"; 测试了小提琴它工作正常。非常感谢,非常感谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-05
  • 2017-01-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-01
相关资源
最近更新 更多