Serialize .Net object to json, controlled using xml attributes

后端 未结 4 1400
隐瞒了意图╮
隐瞒了意图╮ 2020-12-07 00:27

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 N

相关标签:
4条回答
  • 2020-12-07 01:08

    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 讨论(0)
  • 2020-12-07 01:10

    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.
    0 讨论(0)
  • 2020-12-07 01:18

    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();
    
    0 讨论(0)
  • 2020-12-07 01:26

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

    0 讨论(0)
提交回复
热议问题