3

I have an object that needs to be serialized in such a way that both null and "whitespace" (empty or just spaces) values are not serialized. I don't control the object itself and therefore can't set attributes, but I know that all the properties are strings. Setting NullValueHandling to Ignore obviously only gets me part of the way to the solution.

It "seems" (as best I understand) like what I need to do is create a custom DefaultContractResolver but I haven't come up with a solution that works. Here are a couple failed attempts, for reference, that throw no exceptions but have no obvious effect on the serialization either:

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

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

        /* this doesn't work either
        if (property.ValueProvider.GetValue(member) == null ||
            (property.PropertyType == typeof(string) &&
            string.IsNullOrWhiteSpace((string)property.ValueProvider.GetValue(member))))
        {
            property.ShouldSerialize = i => false;
        }*/

        if (property.PropertyType == typeof(string))
        {
            property.ShouldSerialize =
                instance =>
                {
                    try
                    {
                        string s = (string) instance;
                        bool shouldSkip = string.IsNullOrWhiteSpace(s);
                        return !string.IsNullOrWhiteSpace(s);
                    }
                    catch
                    {
                        return true;
                    }
                };
        }

        return property;
    }
}

I'm implementing the resolver by

string str = JsonConvert.SerializeObject(obj, new JsonSerializerSettings
{
    Formatting = Formatting.None;
    ContractResolver = new NoNullWhiteSpaceResolver();
});

Maybe I'm going about this backward but I appreciate any insights people have. I've worked around the issue by using an extension method/reflection to iterate over the properties of the object and setting the value to null if it's "nullorwhitespace" and then using the standard NullValueHandling but I'm hoping I can find a way to configure all of this in the serialization.

2
  • Here are a couple failed attempts, for reference, that throw no exceptions" - catch { return true; } suppresses the invalid cast exception.. Commented Jun 13, 2018 at 15:45
  • @stuartd yes, that's intentional; that note in my question though is superfluous in that case - sorry about that. Commented Jun 13, 2018 at 15:48

1 Answer 1

4

This seems to work:

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

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

        if (property.PropertyType == typeof(string)) {
            property.ShouldSerialize =
                instance => {
                    try {
                        var rawValue = property.ValueProvider.GetValue(instance);
                        if (rawValue == null) {
                            return false;
                        }

                        string stringValue = property.ValueProvider.GetValue(instance).ToString();
                        return !string.IsNullOrWhiteSpace(stringValue);
                    }
                    catch {
                        return true;
                    }
                };
        }

        return property;
    }
}

Using this test class:

public class TestClass {
    public string WhiteSpace => "      ";
    public string Null = null;
    public string Empty = string.Empty;
    public string Value = "value";
}

This is the output:

{"Value":"value"}
Sign up to request clarification or add additional context in comments.

1 Comment

This definitely works. I got close but not close enough ;) thank you!

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.