17

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
}
3
  • Newtonsoft Json.Net james.newtonking.com/projects/json/help/… "also looks for the DataContract and DataMember attributes when determining how JSON is to be serialized and deserialized". Does anyone know if XmlElementAttributes et al are interoperable with DataContractAttributes? Commented Jan 14, 2011 at 18:24
  • A serializer could implement serialization of both Attributes, but I guess that's up to the serializer ... (also see social.msdn.microsoft.com/Forums/en/wcf/thread/…) Commented Jan 20, 2011 at 16:27
  • I've written a small patch for Json.Net which allows the DefaultContractResolver to work with Xml attributes. It works for the simple example above, but I need to write some more tests for more complex examples (AnonymousType etc.) before releasing it. Commented Jan 20, 2011 at 17:37

4 Answers 4

9

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

Sign up to request clarification or add additional context in comments.

3 Comments

Unfortunately this doesn't answer the question. I'm reluctant to add any more attributes to my POCOs - I've hundreds of them with thousands of properties, and wish to steer away from a solution where I have two places to modify if a property name changes.
OK, so update the question with this requirement of yours so that people can contribute. BTW, I got a downvote, was it you?
This is a couple of months old but if you are worried about over decorating your POCOS, why not use a view model for your json attributes? I use this and my POCOS stay nice and clean.
7

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.

3 Comments

Just in case anyone comes across this, it didn't make it into the source for Json.NET. I would be very interested to hear of any other solutions.
I personally like the idea of adding choosing which serializer you want to use, and also, potentially, what order (as James mentioned in the issue).
I believe the archived patch is now here: github.com/iainsproat/ifc-dotnet/blob/master/….
5

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

3 Comments

Would have been cool if you´d show how to use this class. Anyway cool solution +1.
@HimBromBeere does this help?
Yeap, that helped indeed.
0

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.