C# 将.Net对象序列化为json,使用xml属性进行控制
我有一个.Net对象,我一直在将它序列化为Xml,并用Xml属性修饰它。我现在想将同一个对象序列化为Json,最好使用库 我想直接从内存中的.Net对象转换为Json字符串(不需要先序列化为Xml)。我不希望向类添加任何Json属性,而是希望Json序列化程序使用现有的Xml属性C# 将.Net对象序列化为json,使用xml属性进行控制,c#,xml-serialization,json.net,C#,Xml Serialization,Json.net,我有一个.Net对象,我一直在将它序列化为Xml,并用Xml属性修饰它。我现在想将同一个对象序列化为Json,最好使用库 我想直接从内存中的.Net对象转换为Json字符串(不需要先序列化为Xml)。我不希望向类添加任何Json属性,而是希望Json序列化程序使用现有的Xml属性 public class world{ [XmlIgnore] public int ignoreMe{ get; } [XmlElement("foo")] public int bar{ get;
public class world{
[XmlIgnore]
public int ignoreMe{ get; }
[XmlElement("foo")]
public int bar{ get; }
[XmlElement("marco")]
public int polo{ get; }
}
变成
{
"foo":0,
"marco":0
}
使用
[JsonProperty(PropertyName=“foo”)]
属性并设置PropertyName
结果表明,这不是Newtonsoft Json.Net库的现有功能。我已经编写了一个补丁并将其上载到(存档链接):
这考虑到以下几点:
- XmlIgnore的工作原理与JsonIgnore一样
- XmlElementAttribute.ElementName将更改Json属性名
- XmlType.AnonymousType将禁止将对象打印到Json(XmlContractResolver.SuppressAnonymousType属性会改变此行为)这有点不太成熟,因为我必须在学习Json.Net的内部结构的过程中学习
- 下面的类可用于将对象树的部分序列化(和反序列化)为XML,然后再序列化为JSON
用法
[JsonObject]
public class ClassToSerializeWithJson
{
[JsonProperty]
public TypeThatIsJsonSerializable PropertySerializedWithJsonSerializer {get; set; }
[JsonProperty]
[JsonConverter(typeof(JsonXmlConverter<TypeThatIsXmlSerializable>))]
public TypeThatIsXmlSerializable PropertySerializedWithCustomSerializer {get; set; }
}
[JsonObject]
公共类ClassToSerializeWithJson
{
[JsonProperty]
具有JSONSerializer{get;set;}的JSONSerialized属性的公共类型
[JsonProperty]
[JsonConverter(typeof(JsonXmlConverter))]
具有XmlSerializable PropertySerializedWithCustomSerializer{get;set;}的公共类型
}
JsonXmlConverter类
public class JsonXmlConverter<TType> : JsonConverter where TType : class
{
private static readonly XmlSerializer xmlSerializer = new XmlSerializer(typeof(TType));
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var xml = ToXml(value as TType);
using (var stream = new StringReader(xml))
{
var xDoc = XDocument.Load(stream);
var json = JsonConvert.SerializeXNode(xDoc);
writer.WriteRawValue(json);
}
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
{
// consume the 'null' token to set the reader in the correct state
JToken.Load(reader);
return null;
}
var jObj = JObject.Load(reader);
var json = jObj.ToString();
var xDoc = JsonConvert.DeserializeXNode(json);
var xml = xDoc.ToString();
return FromXml(xml);
}
public override bool CanRead => true;
public override bool CanConvert(Type objectType) => objectType == typeof(TType);
private static TType FromXml(string xmlString)
{
using (StringReader reader = new StringReader(xmlString))
return (TType)xmlSerializer.Deserialize(reader);
}
private static string ToXml(TType obj)
{
using (StringWriter writer = new StringWriter())
using (XmlWriter xmlWriter = XmlWriter.Create(writer))
{
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add(String.Empty, String.Empty);
xmlSerializer.Serialize(xmlWriter, obj, ns);
return writer.ToString();
}
}
}
公共类JsonXmlConverter:JsonConverter,其中TType:class
{
私有静态只读XmlSerializer XmlSerializer=新XmlSerializer(typeof(TType));
公共重写void WriteJson(JsonWriter编写器、对象值、JsonSerializer序列化器)
{
var xml=ToXml(值为TType);
使用(var stream=newstringreader(xml))
{
var xDoc=XDocument.Load(流);
var json=JsonConvert.SerializeXNode(xDoc);
WriteRawValue(json);
}
}
公共重写对象ReadJson(JsonReader阅读器,类型objectType,对象existingValue,JsonSerializer序列化程序)
{
if(reader.TokenType==JsonToken.Null)
{
//使用“null”标记将读取器设置为正确状态
JToken.Load(读卡器);
返回null;
}
var jObj=JObject.Load(读卡器);
var json=jObj.ToString();
var xDoc=JsonConvert.DeserializeXNode(json);
var xml=xDoc.ToString();
从xml(xml)返回;
}
public override bool CanRead=>true;
公共覆盖布尔CanConvert(Type objectType)=>objectType==typeof(TType);
私有静态TType FromXml(字符串xmlString)
{
使用(StringReader=新的StringReader(xmlString))
返回(TType)xmlSerializer.Deserialize(读取器);
}
私有静态字符串ToXml(t类型obj)
{
使用(StringWriter=新StringWriter())
使用(XmlWriter=XmlWriter.Create(writer))
{
XmlSerializerNamespaces ns=新的XmlSerializerNamespaces();
ns.Add(String.Empty,String.Empty);
serializer.Serialize(xmlWriter,obj,ns);
返回writer.ToString();
}
}
}
您可以创建一个自定义协定解析程序,允许您对属性进行调整,并在设置XmlIgnoreAttribute的位置将其设置为忽略
public class CustomContractResolver : DefaultContractResolver
{
private readonly JsonMediaTypeFormatter formatter;
public CustomContractResolver(JsonMediaTypeFormatter formatter)
{
this.formatter = formatter;
}
public JsonMediaTypeFormatter Formatter
{
[DebuggerStepThrough]
get { return this.formatter; }
}
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty property = base.CreateProperty(member, memberSerialization);
this.ConfigureProperty(member, property);
return property;
}
private void ConfigureProperty(MemberInfo member, JsonProperty property)
{
if (Attribute.IsDefined(member, typeof(XmlIgnoreAttribute), true))
{
property.Ignored = true;
}
}
}
序列化对象时,可以通过设置JsonSerializerSettings的ContractResolver属性来使用应用此自定义解析器
如果您使用的是WebApi,您可以将其全局设置为应用于所有合同
var config = GlobalConfiguration.Configuration;
var jsonSettings = config.Formatters.JsonFormatter.SerializerSettings;
jsonSettings.ContractResolver = new CustomContractResolver();
不幸的是,这并不能回答这个问题。我不愿意在我的POCO中添加更多的属性-我有数百个属性和数千个属性,我希望避免在属性名称更改时有两个地方需要修改的解决方案。好的,用您的这个要求更新这个问题,以便人们能够作出贡献。顺便说一句,我投了反对票,是你吗?这已经有几个月了,但是如果你担心过度装饰你的POCO,为什么不为你的json属性使用视图模型呢?我用这个,我的POCO保持干净整洁。谢谢你,帮了我的忙!Newtonsoft Json.Net“在确定如何序列化和反序列化Json时,还会查找DataContract和DataMember属性”。有人知道XmlElementAttributes等是否可以与DataContractAttributes互操作吗?序列化程序可以实现两个属性的序列化,但我想这取决于序列化程序。。。(另请参阅)我为Json.Net编写了一个小补丁,它允许DefaultContractResolver处理Xml属性。它适用于上面的简单示例,但在发布它之前,我需要为更复杂的示例(AnonymousType等)编写更多的测试。万一有人遇到这个问题,它没有进入Json.NET的源代码。我很想听到任何其他解决方案。我个人喜欢添加选择要使用的序列化程序的想法,以及潜在的顺序(正如James在本期中提到的)。我相信存档的补丁现在就在这里:。如果您演示如何使用此类,那会很酷。不管怎样,酷的解决方案+1。@HimBromBeere这有帮助吗?是的,确实有帮助。
var config = GlobalConfiguration.Configuration;
var jsonSettings = config.Formatters.JsonFormatter.SerializerSettings;
jsonSettings.ContractResolver = new CustomContractResolver();