【问题标题】:Serialize .Net object to json, controlled using xml attributes将 .Net 对象序列化为 json,使用 xml 属性进行控制
【发布时间】:2011-01-14 00:18:16
【问题描述】:

我有一个 .Net 对象,我已将其序列化为 Xml,并使用 Xml 属性进行装饰。我现在想将相同的对象序列化为 Json,最好使用 Newtonsoft Json.Net 库。

我想直接从内存中的 .Net 对象转到 Json 字符串(无需先序列化为 Xml)。我不希望向类中添加任何 Json 属性,而是希望 Json 序列化程序使用现有的 Xml 属性。

public class world{
  [XmlIgnore]
  public int ignoreMe{ get; }

  [XmlElement("foo")]
  public int bar{ get; }

  [XmlElement("marco")]
  public int polo{ get; }
}

变成

{
  "foo":0,
  "marco":0
}

【问题讨论】:

  • Newtonsoft Json.Net james.newtonking.com/projects/json/help/… “在确定如何序列化和反序列化 JSON 时,还会查找 DataContract 和 DataMember 属性”。有谁知道 XmlElementAttributes 等是否可以与 DataContractAttributes 互操作?
  • 序列化器可以实现两个属性的序列化,但我想这取决于序列化器......(另见social.msdn.microsoft.com/Forums/en/wcf/thread/…
  • 我为 Json.Net 编写了一个小补丁,它允许 DefaultContractResolver 使用 Xml 属性。它适用于上面的简单示例,但在发布之前我需要为更复杂的示例(AnonymousType 等)编写更多测试。

标签: c# xml-serialization json.net


【解决方案1】:

使用[JsonProperty(PropertyName="foo")]属性并设置PropertyName

【讨论】:

  • 不幸的是,这并不能回答问题。我不愿意向我的 POCO 添加任何更多属性 - 我有数百个具有数千个属性的属性,并且希望避开一个解决方案,如果属性名称发生更改,我有两个地方可以修改。
  • 好的,所以用你的这个要求更新问题,以便人们可以做出贡献。顺便说一句,我投了反对票,是你吗?
  • 这已经有几个月了,但是如果您担心过度装饰您的 POCOS,为什么不为您的 json 属性使用视图模型呢?我使用它,我的 POCOS 保持干净整洁。
  • 感谢并帮助了我!
【解决方案2】:

原来这不是 Newtonsoft Json.Net 库的现有功能。我写了一个补丁上传到Json.Net issue tracker(存档链接here):

这允许以下操作:

  • XmlIgnore 的工作方式与 JsonIgnore 类似。
  • XmlElementAttribute.ElementName 将更改 Json 属性名称。
  • XmlType.AnonymousType 将禁止将对象打印到 Json(XmlContractResolver.SuppressAnonymousType 属性会改变这种行为)这有点 hacky,因为我一直在学习 Json.Net 的内部结构.

【讨论】:

  • 以防万一有人遇到这个问题,它并没有成为 Json.NET 的源代码。我很想知道任何其他解决方案。
  • 我个人喜欢添加选择您要使用的序列化程序的想法,以及可能的顺序(正如詹姆斯在问题中提到的那样)。
  • 我相信存档的补丁现在在这里:github.com/iainsproat/ifc-dotnet/blob/master/….
【解决方案3】:

您可以创建一个自定义合同解析器,它允许您调整属性并将它们设置为忽略 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 属性来应用此自定义解析器

https://www.newtonsoft.com/json/help/html/ContractResolver.htm

string json =
    JsonConvert.SerializeObject(
        product, // this is your object that has xml attributes on it that you want ignored
        Formatting.Indented,
        new JsonSerializerSettings { ContractResolver = new CustomResolver() }
        );

如果您使用的是 WebApi,则可以将其全局设置为适用于所有合同。

var config = GlobalConfiguration.Configuration;
var jsonSettings = config.Formatters.JsonFormatter.SerializerSettings;
jsonSettings.ContractResolver = new CustomContractResolver();

【讨论】:

  • 如果你能展示如何使用这个类会很酷。无论如何很酷的解决方案+1。
  • @HimBromBeere 这有帮助吗?
  • 是的,确实有帮助。
【解决方案4】:

下面的类可用于将对象树的部分序列化(和反序列化)为 XML,然后再转换为 JSON。

用法

[JsonObject]
public class ClassToSerializeWithJson
{
    [JsonProperty]
    public TypeThatIsJsonSerializable PropertySerializedWithJsonSerializer {get; set; }

    [JsonProperty]
    [JsonConverter(typeof(JsonXmlConverter<TypeThatIsXmlSerializable>))]
    public TypeThatIsXmlSerializable 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();
        }
    }
}

【讨论】:

    猜你喜欢
    • 2012-03-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-21
    相关资源
    最近更新 更多