【问题标题】:JSON.Net - Change $type field to another name?JSON.Net - 将 $type 字段更改为另一个名称?
【发布时间】:2012-02-28 21:54:38
【问题描述】:

在使用 Json.Net 时,我了解如何将 $type 属性放入呈现的 json 中,但是有没有办法更改该字段名称?我需要使用“__type”而不是“$type”。

【问题讨论】:

  • 我也需要这个,例如JSON-LD使用@type

标签: json.net


【解决方案1】:

http://json.codeplex.com/workitem/22429

“我宁愿保持 $type 硬编码和一致。”

与我想知道的一致吗?

http://json.codeplex.com/workitem/21989

我宁愿不 - 我认为这对我来说太具体了,我不 想要过度设置。在某个时候,我可能会 实现这个 - http://json.codeplex.com/workitem/21856 - 允许 人们在 JSON 中读/写自己的元属性,而你 可以使用新的属性名称重新实现类型名称处理。这 其他选择只是为自己修改源代码 该属性名称。

最近,Issue #36: Customizable $type property name feature

我宁愿不要

这是我的解决方案...

json.Replace("\"$type\": \"", "\"type\": \"");

【讨论】:

【解决方案2】:

看起来这在Newtonsoft.Json.Serialization.JsonTypeReflector 中被硬编码为public const string TypePropertyName = "$type";,不幸的是这是内部静态类。

我自己也需要这个,我唯一能想到的就是拥有 json.net 本身的自定义修改版本。这当然是一个主要的皮塔饼。

【讨论】:

  • 不幸的是,由于 Json.Net 在许多情况下很难使用,我几乎不得不完全放弃我所走的道路。这只是一个例子。
  • 我自己正在研究如何在服务器端使用 C# 编写并使用 Json.NET,可以反序列化从使用 Jackson 的 Android 应用程序发送的 JSON。在杰克逊我可以设置使用“$type”,但它无论如何都不起作用。
【解决方案3】:

在序列化时,有一个很好的方法来覆盖属性名称:

public class CustomJsonWriter : JsonTextWriter
{
    public CustomJsonWriter(TextWriter writer) : base(writer)
    {
    }

    public override void WritePropertyName(string name, bool escape)
    {
        if (name == "$type") name = "__type";
        base.WritePropertyName(name, escape);
    }
}

var serializer = new JsonSerializer();
var writer = new StreamWriter(stream) { AutoFlush = true };
serializer.Serialize(new CustomJsonWriter(writer), objectToSerialize);

我还没有尝试过反序列化,但在最坏的情况下我可以使用:

json.Replace("\"__type": \"", "\"type\": \"$type\");

【讨论】:

  • 读者有类似的解决方案吗?我正在尝试反序列化对象,但是我的 Json 中的 $types 非常丑陋/复杂,并且想重命名它们。谢谢:-)
【解决方案4】:

我必须为我的 UI REST API 这样做,因为 Angular.js disregards 字段名称以美元符号 ($) 开头。

因此,这里有一个解决方案,它将整个 Web API 的 $type 重命名为 __type,并且适用于序列化反序列化。

为了能够使用自定义JsonWriter 和自定义JsonReader(如该问题的其他答案中所建议),我们必须继承JsonMediaTypeFormatter 并覆盖相应的方法:

internal class CustomJsonNetFormatter : JsonMediaTypeFormatter
{
    public override JsonReader CreateJsonReader(Type type, Stream readStream, Encoding effectiveEncoding)
    {
        return new CustomJsonReader(readStream, effectiveEncoding);
    }

    public override JsonWriter CreateJsonWriter(Type type, Stream writeStream, Encoding effectiveEncoding)
    {
        return new CustomJsonWriter(writeStream, effectiveEncoding);
    }

    private class CustomJsonWriter : JsonTextWriter
    {
        public CustomJsonWriter(Stream writeStream, Encoding effectiveEncoding)
            : base(new StreamWriter(writeStream, effectiveEncoding))
        {
        }

        public override void WritePropertyName(string name, bool escape)
        {
            if (name == "$type") name = "__type";
            base.WritePropertyName(name, escape);
        }
    }

    private class CustomJsonReader : JsonTextReader
    {
        public CustomJsonReader(Stream readStream, Encoding effectiveEncoding)
            : base(new StreamReader(readStream, effectiveEncoding))
        {
        }

        public override bool Read()
        {
            var hasToken = base.Read();
            if (hasToken && TokenType == JsonToken.PropertyName && Value != null && Value.Equals("__type"))
            {
                SetToken(JsonToken.PropertyName, "$type");
            }
            return hasToken;
        }
    }
}

当然,您需要在WebApiConfig 中注册自定义格式化程序。因此,我们将默认的 Json.NET 格式化程序替换为我们的自定义格式化程序:

config.Formatters.Remove(config.Formatters.JsonFormatter);
config.Formatters.Add(new CustomJsonNetFormatter());

完成。

【讨论】:

  • 我喜欢这个解决方案!通过一个小的自定义,我不再需要使用冗长的类型名称 Namespace.Type, AssemblyName 但也可以重写它;-)
【解决方案5】:

我们有这个需求,所以我创建了一个自定义 JsonReader。我们正在我们的 MS Web 服务中使用带有复杂数据模型的 rest,需要用“$type”替换“__type”属性。

class MSJsonReader : JsonTextReader
{
    public MSJsonTextReader(TextReader reader) : base(reader) { }

    public override bool Read()
    {
        var hasToken = base.Read();

        if (hasToken && base.TokenType == JsonToken.PropertyName && base.Value != null && base.Value.Equals("__type"))
            base.SetToken(JsonToken.PropertyName, "$type");

        return hasToken;
    }
}

这是我们如何使用它的。

using(JsonReader jr = new MSJsonTextReader(sr))
{
    JsonSerializer s = new JsonSerializer();
    s.DateFormatHandling = DateFormatHandling.MicrosoftDateFormat;
    s.NullValueHandling = NullValueHandling.Ignore;
    s.TypeNameHandling = TypeNameHandling.Auto; // Important!
    s.Binder = new MSRestToJsonDotNetSerializationBinder("Server.DataModelsNamespace", "Client.GeneratedModelsNamespace");

    T deserialized = s.Deserialize<T>(jr);

    return deserialized;
}

这里是我们的MSRestToJsonDotNetSerializationBinder,完成了MS rest和Json.Net的兼容。

class MSRestToJsonDotNetSerializationBinder : System.Runtime.Serialization.SerializationBinder
{
    public string ServiceNamespace { get; set; }
    public string LocalNamespace { get; set; }

    public MSRestToJsonDotNetSerializationBinder(string serviceNamespace, string localNamespace)
    {
        if (serviceNamespace.EndsWith("."))
            serviceNamespace = serviceNamespace.Substring(0, -1);

        if(localNamespace.EndsWith("."))
            localNamespace = localNamespace.Substring(0, -1);

        ServiceNamespace = serviceNamespace;
        LocalNamespace = localNamespace;
    }

    public override void BindToName(Type serializedType, out string assemblyName, out string typeName)
    {
        assemblyName = null;
        typeName = string.Format("{0}:#{1}", serializedType.Name, ServiceNamespace); // MS format
    }

    public override Type BindToType(string assemblyName, string typeName)
    {
        string jsonDotNetType = string.Format("{0}.{1}", LocalNamespace, typeName.Substring(0, typeName.IndexOf(":#")));
        return Type.GetType(jsonDotNetType);
    }
}

【讨论】:

    【解决方案6】:

    你也可以这样做:

    [JsonConverter(typeof(JsonSubtypes), "ClassName")]
    public class Annimal
    {
        public virtual string ClassName { get; }
        public string Color { get; set; }
    }
    

    您将需要JsonSubtypes 不属于Newtonsoft.Json 项目的转换器。

    【讨论】:

      【解决方案7】:

      还有另一个选项允许序列化Json.NET 中的自定义类型属性名称。这个想法是不要写默认的$type属性,而是引入类型名称作为类本身的属性。

      假设我们有一个Location 类:

      public class Location
      {
          public double Latitude { get; set; }
      
          public double Longitude { get; set; }
      }
      

      首先,我们需要引入类型属性名并修改类,如下所示:

      public class Location
      {
          [JsonProperty("__type")]
          public string EntityTypeName
          {
      
              get
              {
                  var typeName = string.Format("{0}, {1}", GetType().FullName, GetType().Namespace);
                  return typeName;
              }
          }
      
          public double Latitude { get; set; }
      
          public double Longitude { get; set; }
      }
      

      然后,将JsonSerializerSettings.TypeNameHandling 设置为TypeNameHandling.None 以使反序列化器跳过默认$type 属性的呈现。

      就是这样。

      示例

      var point = new Location() { Latitude = 51.5033630, Longitude = -0.1276250 };
      
      var jsonLocation = JsonConvert.SerializeObject(point, new JsonSerializerSettings
      {
           TypeNameHandling = TypeNameHandling.None,   //do not write type property(!)
      });
      Console.WriteLine(jsonLocation);
      

      结果

      {"__type":"Namespace.Location, Namespace","Latitude":51.503363,"Longitude":-0.127625}
      

      【讨论】:

      • 我看不出反序列化将如何确定您的解决方案的正确类型。你能解释一下吗?
      • 要反序列化,请尝试JsonCreationConverter,例如见stackoverflow.com/questions/8030538
      【解决方案8】:

      使用自定义转换器应该可以完成工作。

      public CustomConverter : JsonConverter
      {
          public override bool CanWrite => true;
          public override bool CanRead => true;
      
          public override object ReadJson(JsonReader reader,
              Type objectType,
              object existingValue,
              JsonSerializer serializer)
              => throw new NotImplementedException();
      
          public override void WriteJson(JsonWriter writer,
              object value,
              JsonSerializer serializer)
          {
              var jOjbect = (JObject)JToken.FromObject(value);
              jOjbect.Add(new JProperty("type", value.GetType().Name));
              jOjbect.WriteTo(writer);
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2016-04-10
        • 1970-01-01
        • 2015-01-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多