Deserialize json with auto-trimming strings

后端 未结 3 1914
我寻月下人不归
我寻月下人不归 2020-12-20 12:20

I use Newtonsoft.Json library

Is there a way to trim spaces from any string data during deserialization?

class Program
{
    class Person
    {
              


        
相关标签:
3条回答
  • 2020-12-20 12:55

    The solution provide above didnt work for me. I modified Sam Fisher solution and combined it with Timmerz solution. how to get both fields and properties in single call via reflection?

    public sealed class TrimAttribute : Attribute {
    }
    
    public static class TrimConverterExtension {
      public static void SetValue(this MemberInfo member, object property, object value) {
         switch (member.MemberType) {
            case MemberTypes.Property:
               ((PropertyInfo)member).SetValue(property, value, null);
               break;
            case MemberTypes.Field:
               ((FieldInfo)member).SetValue(property, value);
               break;
            default:
               throw new Exception("Property must be of type FieldInfo or PropertyInfo");
         }
      }
    
      public static object GetValue(this MemberInfo member, object property) {
         switch (member.MemberType) {
            case MemberTypes.Property:
               return ((PropertyInfo)member).GetValue(property, null);
            case MemberTypes.Field:
               return ((FieldInfo)member).GetValue(property);
            default:
               throw new Exception("Property must be of type FieldInfo or PropertyInfo");
         }
      }
    
      public static Type GetMemberType(this MemberInfo member) {
         switch (member.MemberType) {
            case MemberTypes.Field:
               return ((FieldInfo)member).FieldType;
            case MemberTypes.Property:
               return ((PropertyInfo)member).PropertyType;
            case MemberTypes.Event:
               return ((EventInfo)member).EventHandlerType;
            default:
               throw new ArgumentException("MemberInfo must be if type FieldInfo, PropertyInfo or EventInfo", "member");
         }
      }
    }
    
    public class TrimConverter<T> : JsonConverter where T : new() {
      public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) {
      }
    
      public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
         var jObject = JObject.Load(reader);
         var obj = new T();
         serializer.Populate(jObject.CreateReader(), obj);
    
         //Looks for the trim attribute on the property
         const BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.Instance;
         IEnumerable<MemberInfo> members = objectType.GetFields(bindingFlags).Cast<MemberInfo>()
             .Concat(objectType.GetProperties(bindingFlags))
             .Where(p => p.GetMemberType() == typeof(string))
             .Where(p => Attribute.GetCustomAttributes(p).Any(u => (Type)u.TypeId == typeof(TrimAttribute)))
    
             .ToArray();
    
         foreach (var fieldInfo in members) {
            var val = (string)fieldInfo.GetValue(obj);
            if (!string.IsNullOrEmpty(val)) {
               fieldInfo.SetValue(obj, val.Trim());
            }
         }
    
         return obj;
      }
    
      public override bool CanConvert(Type objectType) {
         return objectType.IsAssignableFrom(typeof(T));
      }
    }
    
    0 讨论(0)
  • 2020-12-20 12:57

    You could write your own JsonConverter:

    public class TrimmingConverter : JsonConverter
    {
        public override bool CanRead => true;
        public override bool CanWrite => false;
    
        public override bool CanConvert(Type objectType) => objectType == typeof(string);
    
        public override object ReadJson(JsonReader reader, Type objectType,
                                        object existingValue, JsonSerializer serializer)
        {
            return ((string)reader.Value)?.Trim();
        }
    
        public override void WriteJson(JsonWriter writer, object value, 
                                       JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }
    }
    

    You can use it like this to apply to all string fields:

    var json = @"{ name:"" John "" }"
    var p = JsonConvert.DeserializeObject<Person>(json, new TrimmingConverter());
    Console.WriteLine("Name is: \"{0}\"", p.Name);
    //Name is: "John"
    

    Or you can apply this to certain fields only:

    public class Person
    {
        [JsonProperty("name")]
        [JsonConverter(typeof(TrimmingConverter))] // <-- that's the important line
        public string Name { get; set; }
        [JsonProperty("other")]
        public string Other { get; set; }
    }
    
    var json = @"{ name:"" John "", other:"" blah blah blah "" }"
    var p = JsonConvert.DeserializeObject<Person>(json);
    Console.WriteLine("Name is: \"{0}\"", p.Name);
    Console.WriteLine("Other is: \"{0}\"", p.Other);
    
    //Name is: "John"
    //Other is: " blah blah blah "
    
    0 讨论(0)
  • 2020-12-20 13:00

    In .net core 3.1 you can use the System.Text.Json to achieve this.

        /// <summary>
        /// Trim spaces
        /// </summary>
        public class TrimmingConverter : JsonConverter<string>
        {
            /// <summary>
            /// Trim the input string
            /// </summary>
            /// <param name="reader">reader</param>
            /// <param name="typeToConvert">Object type</param>
            /// <param name="options">Existing Value</param>
            /// <returns></returns>
            public override string Read(
              ref Utf8JsonReader reader,
              Type typeToConvert,
              JsonSerializerOptions options) => reader.GetString()?.Trim();
    
            /// <summary>
            /// Trim the output string
            /// </summary>
            /// <param name="writer">Writer</param>
            /// <param name="dateTimeValue">value</param>
            /// <param name="options">serializer</param>
            public override void Write(
                Utf8JsonWriter writer,
                string dateTimeValue,
                JsonSerializerOptions options) => writer.WriteStringValue(dateTimeValue?.Trim());
        }
    
    0 讨论(0)
提交回复
热议问题