Remove empty string properties from json serialized object

33,902

Solution 1

Just decorating the properties [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] ONLY should do what you want. Unless the property is getting set to an empty string.

Just wondering, why do you need the DataMemeber attribute?

Here is a link to a working dotnetfiddle

using System;
using Newtonsoft.Json;
using System.ComponentModel;

public class Program
{

    public static void Main()
    {
        var user = new User();

        user.UserID = "1234";
        user.ssn = "";

        var settings = new JsonSerializerSettings();

        settings.NullValueHandling = NullValueHandling.Ignore;
        settings.DefaultValueHandling = DefaultValueHandling.Ignore;


        Console.WriteLine(JsonConvert.SerializeObject(user, settings));
    }
}

public class User
{
    [DefaultValue("")]
    public string UserID { get; set; }

    [DefaultValue("")]
    public string ssn { get; set; }

    [DefaultValue("")]
    public string empID { get; set; }

    [DefaultValue("")]
    public string schemaAgencyName { get; set; }

    [DefaultValue("")]
    public string givenName { get; set; }

    [DefaultValue("")]
    public string familyName { get; set; }

    [DefaultValue("")]
    public string password { get; set; }
}

Solution 2

You can also use two annotations as follows:

[DefaultValue("")]
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public string Category { get; set; }

Solution 3

Although the accepted answers works, it also removes integer properties of zero value. I was looking for something more generic to work with large objects.

Found a great answer here: https://codearticles.ru/articles/2905?AspxAutoDetectCookieSupport=1

And consolidated it for our use case as below:

public class ShouldSerializeContractResolver : DefaultContractResolver
{
    public static readonly ShouldSerializeContractResolver Instance = new ShouldSerializeContractResolver();

    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        JsonProperty property = base.CreateProperty(member, memberSerialization);

        if (property.PropertyType == typeof(string))
        {
            // Do not include emptry strings
            property.ShouldSerialize = instance =>
            {
                return !string.IsNullOrWhiteSpace(instance.GetType().GetProperty(member.Name).GetValue(instance, null) as string);
            };
        }
        else if (property.PropertyType == typeof(DateTime))
        {
            // Do not include zero DateTime
            property.ShouldSerialize = instance =>
            {
                return Convert.ToDateTime(instance.GetType().GetProperty(member.Name).GetValue(instance, null)) != default(DateTime);
            };
        }
        else if (typeof(IEnumerable).IsAssignableFrom(property.PropertyType))
        {
            // Do not include zero-length lists
            switch (member.MemberType)
            {
                case MemberTypes.Property:
                    property.ShouldSerialize = instance =>
                    {
                        var enumerable = instance.GetType().GetProperty(member.Name).GetValue(instance, null) as IEnumerable;
                        return enumerable != null ? enumerable.GetEnumerator().MoveNext() : false;
                    };
                    break;
                case MemberTypes.Field:
                    property.ShouldSerialize = instance =>
                    {
                        var enumerable = instance.GetType().GetField(member.Name).GetValue(instance) as IEnumerable;
                        return enumerable != null ? enumerable.GetEnumerator().MoveNext() : false;
                    };
                    break;
            }
        }
        return property;
    }
}

This can be used as follows:

JsonConvert.SerializeObject(o,
    Newtonsoft.Json.Formatting.None,
    new JsonSerializerSettings
    {
        NullValueHandling = NullValueHandling.Ignore,
        ContractResolver = ShouldSerializeContractResolver.Instance
    });

Solution 4

i have done this with a converter.

using System;

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace TestApp.JsonConverterResolver
{
    public class IgnoreEmptyStringsConverter : JsonConverter
    {
    #region Methods

        public override bool CanConvert(Type objectType)
        {
            return objectType == typeof(string);
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue,
                                        JsonSerializer serializer)
        {
            var theValue = reader.Value?.ToString();

            return !string.IsNullOrWhiteSpace(theValue) ? theValue : null;
        }

        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            if (!string.IsNullOrWhiteSpace(value.ToString()))
            {
                JToken token = JToken.FromObject(value.ToString(), serializer);
                token.WriteTo(writer);
                return;
            }

            writer.WriteNull();
        }

    #endregion
    }
}

Example person model class:

public class Person
{
    public string Name { get; set; }
}

And the ueage:

var serializerSettings = new JsonSerializerSettings
     {
         Formatting           = Newtonsoft.Json.Formatting.Indented,
         NullValueHandling    = Newtonsoft.Json.NullValueHandling.Ignore,
         Converters           = new List<JsonConverter> {new IgnoreEmptyStringsConverter()}
     };

var person = JsonConvert.DeserializeObject<Person>("{ \"Name\":\"\" }", serializerSettings);

var jsonPerson = JsonConvert.SerializeObject(new Person { Name = "" }, serializerSettings);

I just wrote that out of my head. But I think that's how I solved it at some point. Maybe it helps someone.

Share:
33,902
RookieAppler
Author by

RookieAppler

Updated on July 09, 2022

Comments

  • RookieAppler
    RookieAppler almost 2 years

    I have a class. It has several properties lets say 10. Out of these 10, 3 are filled with data remaining 7 are blank.i.e. empty strings "" Used this link as reference. I would like only NON-NULL and NON-EMPTY string properties to be shown. But the end output has all 10 properties. I want only to see 3.

    namespace Mynamespace.ValueObjects
    {
    [DataContract]
    public class User
    {
          [DataMember(Name ="userID", IsRequired = false,EmitDefaultValue = false)]
        public string userID { get; set; }
          [DataMember(Name ="ssn", IsRequired = false,EmitDefaultValue = false)]
        public string ssn { get; set; }
          [DataMember(Name ="empID", IsRequired = false,EmitDefaultValue = false)]
        public string empID { get; set; }
          [DataMember(Name ="schemaAgencyName", IsRequired = false,EmitDefaultValue = false)]
        public string schemaAgencyName { get; set; }
          [DataMember(Name ="givenName", IsRequired = false,EmitDefaultValue = false)]
        public string givenName { get; set; }
          [DataMember(Name ="familyName", IsRequired = false,EmitDefaultValue = false)]
        public string familyName { get; set; }
          [DataMember(Name ="password", IsRequired = false,EmitDefaultValue = false)]
        public string password { get; set; }
          ....
    
    }
    

    }

    I also tried with

     [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
    

    as the attribute too. No luck. I also did like this

     var t = JsonConvert.SerializeObject(usr, Newtonsoft.Json.Formatting.None,
                                                    new JsonSerializerSettings
                                                        {NullValueHandling = NullValueHandling.Ignore});
    

    where 'usr' is the User instance. By no luck I mean, the 't' comes back with all the 10 properties

    {"userID":"vick187","ssn":"","empID":"","schemaAgencyName":"","givenName":"","familyName":"","password":"pwd1234",...}
    

    So as you can see only userID and password are populated. But I have ssn, empID etc still showing up. I only want userID and password. Any help would be appreciated.