开发者

Serialize .Net object to json, controlled using xml attributes

I have a .Net object which I've been serializing to Xml and is decorated with Xml attributes. I would now like to serialize the same object to Json, preferably using the Newtonsoft Json.Net library.

I'd like to go directly from the .Net object in memory to a Json string (without serializing to Xml first). 开发者_开发技巧 I do not wish to add any Json attributes to the class, but instead would like for the Json serializer to use the existing Xml attributes.

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

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

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

becomes

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


Use [JsonProperty(PropertyName="foo")] Attribute and set the PropertyName.


Turns out this wasn't an existing feature of the Newtonsoft Json.Net library. I've written a patch and uploaded it to the Json.Net issue tracker (archived link here):

This allows for the following:

  • XmlIgnore works just like JsonIgnore.
  • XmlElementAttribute.ElementName will alter the Json property name.
  • XmlType.AnonymousType will suppress objects from being printed to Json (XmlContractResolver.SuppressAnonymousType property alters this behaviour) this is a little bit hacky, as I've had to learn Json.Net's internals as I've been going.


You could create a custom contract resolver which would allow you to make adjustments to the properties and set them to ignore where an XmlIgnoreAttribute is set.

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;
        }            
    }
}

You can use apply this custom resolver by setting the ContractResolver property of the JsonSerializerSettings when serializing an object

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() }
        );

If you're using WebApi you can set it globally to apply to all contracts.

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


The class below can be used to serialize (and deserialize) parts of the object tree to XML and then to JSON.

Usage

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

    [JsonProperty]
    [JsonConverter(typeof(JsonXmlConverter<TypeThatIsXmlSerializable>))]
    public TypeThatIsXmlSerializable PropertySerializedWithCustomSerializer {get; set; }
}

JsonXmlConverter class

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();
        }
    }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜