3

I have a class:

public class CustomResponse
{
    [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
    public string Message {get; set; }
    [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
    public string Details {get; set; }
}

Then I'm trying to deserialize JSON string to this class:

var settings = new JsonSerializerSettings
    {
        NullValueHandling.Ignore,
        MissingMemberHandling.Ignore,
    };
var customResponse = JsonConvert.Deserialize<CustomResponse>(jsonString, settings);

My JSON string for example:

{"DocumentId":"123321", "DocumentNumber":"ABC123"}

As a result I have an object which have all properties is NULL, but customResponse is not NULL. How do I get NULL in result?

Jason Aller
  • 3,541
  • 28
  • 38
  • 38

2 Answers2

3

If you want to avoid creating a custom JsonConverter, you can use the following extension method:

public static class Exts
{
    public static T OrDefaultWhen<T>(this T obj, Func<T, bool> predicate)
    {
        return predicate(obj) ? default(T) : obj;
    }
}

Usage:

var jsonString = @"{
    Message: null,
    Details: null
}";

var res = JsonConvert.DeserializeObject<CustomResponse>(jsonString)
                     .OrDefaultWhen(x => x.Details == null && x.Message == null);
haim770
  • 48,394
  • 7
  • 105
  • 133
2

You could create a custom JsonConverter that allocates and populates your object, then checks afterwards to see whether all properties are null, using the value returned by the JsonProperty.ValueProvider:

public class ReturnNullConverter<T> : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return typeof(T).IsAssignableFrom(objectType);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
            return null;

        // Get the contract.
        var contract = (JsonObjectContract)serializer.ContractResolver.ResolveContract(objectType);

        // Allocate the object (it must have a parameterless constructor)
        existingValue = existingValue ?? contract.DefaultCreator();

        // Populate the values.
        serializer.Populate(reader, existingValue);

        // This checks for all properties being null.  Value types are never null, however the question
        // doesn't specify a requirement in such a case.  An alternative would be to check equality
        // with p.DefaultValue
        // http://www.newtonsoft.com/json/help/html/P_Newtonsoft_Json_Serialization_JsonProperty_DefaultValue.htm
        if (contract.Properties
            .Where(p => p.Readable)
            .All(p => object.ReferenceEquals(p.ValueProvider.GetValue(existingValue), null)))
            return null;

        return existingValue;
    }

    public override bool CanWrite { get { return false; } }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

Then use it like:

var settings = new JsonSerializerSettings
{
    NullValueHandling = NullValueHandling.Ignore,
    MissingMemberHandling = MissingMemberHandling.Ignore,
    Converters = { new ReturnNullConverter<CustomResponse>() },
};
var customResponse = JsonConvert.DeserializeObject<CustomResponse>(jsonString, settings);

Sample fiddle.

However, in comments you wrote, if CustomResponse is NULL, then service return a correct response and i try to deserialize to OtherCustomResponse. In that case, consider using a polymorphic converter such as the ones from How to implement custom JsonConverter in JSON.NET to deserialize a List of base class objects? or Deserializing polymorphic json classes without type information using json.net

Community
  • 1
  • 1
dbc
  • 104,963
  • 20
  • 228
  • 340