当使用Json.Net时,我理解如何将$ type属性放入渲染的json中,但有没有办法更改该字段名称?我需要使用“__type”而不是“$ type”。
答案 0 :(得分:17)
看起来这是public const string TypePropertyName = "$type";
中的Newtonsoft.Json.Serialization.JsonTypeReflector
硬编码,遗憾的是内部静态类。
我自己需要这个,我唯一能想到的就是拥有json.net本身的自定义修改版本。这当然是一个主要的皮塔饼。
答案 1 :(得分:16)
http://json.codeplex.com/workitem/22429
“我宁愿保持$ type硬编码和一致。”
与我的想法一致吗?
http://json.codeplex.com/workitem/21989
我宁愿不 - 我觉得这对我来说太具体了,我没有 想要超越设置。在某些时候我可能会 实现这一点 - http://json.codeplex.com/workitem/21856 - 允许 人们在JSON中读取/写入自己的元属性和你 可以使用新的属性名称重新实现类型名称处理。该 其他选项只是修改自己拥有的源代码 属性名称。
这是我的解决方案......
json.Replace("\"$type\": \"", "\"type\": \"");
答案 2 :(得分:4)
我们需要这个,所以我创建了一个自定义的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);
}
}
答案 3 :(得分:4)
序列化时,有一种很好的方法来覆盖属性名称:
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\");
答案 4 :(得分: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());
完成。
答案 5 :(得分:2)
你也可以这样做:
[JsonConverter(typeof(JsonSubtypes), "ClassName")]
public class Annimal
{
public virtual string ClassName { get; }
public string Color { get; set; }
}
您需要JsonSubtypes
转换器不属于Newtonsoft.Json
项目。
答案 6 :(得分:1)
还有另一个选项允许在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}
答案 7 :(得分:0)
使用自定义转换器可以完成工作。
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);
}
}