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();
}
}
}
精彩评论