47

I have a class set up as follows:

public class Foo
{
    public string string1 { get; set; }
    public string string2 { get; set; }
    public string string3 { get; set; }
}

I am using Json.Net to deserialize the following Json Response:

[
    {
        "number1": 1,
        "number2": 12345678901234567890,
        "number3": 3
    },
    {
        "number1": 9,
        "number2": 12345678901234567890,
        "number3": 8
    }
]

Deserialization code:

string json = @"[
    {
        ""number1"": 1,
        ""number2"": 12345678901234567890,
        ""number3"": 3
    },
    {
        ""number1"": 9,
        ""number2"": 12345678901234567890,
        ""number3"": 8
    }
]"

List<Foo> foos = JsonConvert.DeserializeObject<List<Foo>>(json);

The value in number2 exceeds an Int64, but I don't really care about retrieving that value. Is there a way to cast the number2 property to a string, or fully ignore it during deserialization?

I have tried adding the [JsonConverter(typeof(string))] attribute to the string2 property, but recieve the error: Error creating System.String. I have also tried setting typeof(decimal).

I have also tried using [JsonIgnore] but that doesn't work.

3
  • 2
    I solved the issue by using a Regex.Replace() to remove the entry: string fixedResponse = Regex.Replace(json, "\\\"number2\\\": \\d+, " ,String.Empty); Commented Oct 6, 2012 at 2:22
  • Why don't you post a proper answer? Commented May 26, 2017 at 4:34
  • stackoverflow.com/questions/38054986/… Commented Feb 6, 2019 at 22:09

9 Answers 9

47

You can use MissingMemberHandling property of the JsonSerializerSettings object.

Example usage:

var jsonSerializerSettings = new JsonSerializerSettings();
jsonSerializerSettings.MissingMemberHandling = MissingMemberHandling.Ignore;

JsonConvert.DeserializeObject<YourClass>(jsonResponse, jsonSerializerSettings);

More info here.

Sign up to request clarification or add additional context in comments.

2 Comments

he is asking to ignore specific key not handle missing key, you answer is irrelevant to the question
it's interesting still how many of us were searching for actually this answer - i.e. we had a different question, but the answer we got was right. i am almost feeling surreal
12

This is a lame workaround but you could make a method to manually load the json. If it's too much data to load without an automatic deserializer just remove the nodes that you don't want. This is a lot slower though.

public static List<Foo> FromJson(string input) {
    var json = JToken.Parse(input);
    json["key"].Remove();
    var foo = JsonConvert.DeserializeObject<List<Foo>>(json.ToString());

}

This is an interesting problem I wonder if anyone has a better solution for it.

2 Comments

This code errors at JToken.Parse(input), it still can't parse a uInt64 :/
That sucks it looks like Regex is your best friend right now. Maybe submit an issue with the Json.net people.
10

Here's the Newtonsoft Json preferred way to ignore a property without having to modify the class as based on http://james.newtonking.com/json/help/index.html?topic=html/ReducingSerializedJSONSize.htm

This one is used to ignore lazy reference properties of EF or Linq2Sql

public class DynamicContractResolver : DefaultContractResolver
{
    protected override IList<JsonProperty> CreateProperties(Type type, 
        MemberSerialization memberSerialization)
    {
        Func<Type,bool> includeProperty = t => t.IsValueType || t.Namespace.StartsWith("System") && t.Namespace.StartsWith("System.Data")==false; 
        IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization);
        var allProperties = properties.Select (p => new{p.PropertyName,Including=includeProperty(p.PropertyType), p.PropertyType});//.Dump("props");
        var warnProperties=allProperties.Where (a =>a.Including && a.PropertyType.IsValueType==false && a.PropertyType.Name.IsIgnoreCaseMatch("String")==false) ;

        //linq pad debugging helper
        //var propertyTypesSerializing= allProperties.Where (p => p.Including).Select (p => p.PropertyType).Distinct().OrderBy (p => p.Name).Dump();

        if(warnProperties.Any())
        {
            //LinqPad helper
            //Util.Highlight(warnProperties.ToArray()).Dump("warning flag raised, aborting");
            throw new ArgumentOutOfRangeException();
        }

        properties = properties.Where(p =>includeProperty(p.PropertyType)).ToList();
        return properties;
    }
}

All the .Dump() calls are just linqpad debugging helpers, not needed method calls.

sample usage:

var inactives = from am in Aspnet_Memberships
        join mm in Member_members on am.UserId equals mm.Member_guid
        where mm.Is_active==false && mm.Org_id==1
        select new{am,mm};
        //inactives.Take(4).ToArray().Dump();
        var serialized = JsonConvert.SerializeObject(
            inactives.Skip(1).Select(i => i.mm).First(), 
            new  JsonSerializerSettings()
            {
                ContractResolver = new DynamicContractResolver(), 
                PreserveReferencesHandling = PreserveReferencesHandling.None,
                ReferenceLoopHandling= ReferenceLoopHandling.Ignore
            }); 
            //.Dump();

1 Comment

.IsIgnoreCaseMatch?, Does that mean .Equals("String", StringComparison.[xIgnoreCase]) ?
3

Similar to @Maslow's solution, you can use another general purpose "ignorer":

var jsonResolver = new IgnorableSerializerContractResolver();
// ignore your specific property
jsonResolver.Ignore(typeof(Foo), "string2");
// ignore single datatype
jsonResolver.Ignore(typeof(System.Data.Objects.DataClasses.EntityObject));
var jsonSettings = new JsonSerializerSettings() { ReferenceLoopHandling = ReferenceLoopHandling.Ignore, ContractResolver = jsonResolver };

4 Comments

That is for ignores during serialization, this question is about deserialization.
@Alrehamy what? To quote the question > "...or fully ignore it during deserialization"
Years later based on @ohad-bitton's answer I think the resolver doesn't work both ways. Oh well.
I ran into the same thing, but was able to fix it by overriding the CreateProperties method: ` protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization) { var properties = base.CreateProperties(type, memberSerialization); foreach (var p in Ignores.SelectMany((type) => type.Value)) { properties.Add(new JsonProperty() { PropertyName = p }); } return properties; }`
3

this code worked like a charm to me:

using System.Reflection;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
public class PropertyRenameAndIgnoreSerializerContractResolver : DefaultContractResolver
{
    private readonly Dictionary<Type, HashSet<string>> _ignores;
    private readonly Dictionary<Type, Dictionary<string, string>> _renames;

    public PropertyRenameAndIgnoreSerializerContractResolver()
    {
        _ignores = new Dictionary<Type, HashSet<string>>();
        _renames = new Dictionary<Type, Dictionary<string, string>>();
    }

    public void IgnoreProperty(Type type, params string[] jsonPropertyNames)
    {
        if (!_ignores.ContainsKey(type))
            _ignores[type] = new HashSet<string>();

        foreach (var prop in jsonPropertyNames)
            _ignores[type].Add(prop);
    }

    public void RenameProperty(Type type, string propertyName, string newJsonPropertyName)
    {
        if (!_renames.ContainsKey(type))
            _renames[type] = new Dictionary<string, string>();

        _renames[type][propertyName] = newJsonPropertyName;
    }

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

        if (IsIgnored(property.DeclaringType, property.PropertyName))
        {
            property.ShouldSerialize = i => false;
            property.Ignored = true;
        }

        if (IsRenamed(property.DeclaringType, property.PropertyName, out var newJsonPropertyName))
            property.PropertyName = newJsonPropertyName;

        return property;
    }

    private bool IsIgnored(Type type, string jsonPropertyName)
    {
        if (!_ignores.ContainsKey(type))
            return false;

        return _ignores[type].Contains(jsonPropertyName);
    }

    private bool IsRenamed(Type type, string jsonPropertyName, out string newJsonPropertyName)
    {
        Dictionary<string, string> renames;

        if (!_renames.TryGetValue(type, out renames) || !renames.TryGetValue(jsonPropertyName, out newJsonPropertyName))
        {
            newJsonPropertyName = null;
            return false;
        }

        return true;
    }
}

//ignore number2 in Foo Example

public class Foo
{
public string number1 { get; set; }
public string number2 { get; set; }
public string number3 { get; set; }
}
    string Foojson = @"[
    {
        ""number1"": 1,
        ""number2"": 12345678901234567890,
        ""number3"": 3
    },
    {
        ""number1"": 9,
        ""number2"": 12345678901234567890,
        ""number3"": 8
    }
]";
var jsonResolverFoo = new PropertyRenameAndIgnoreSerializerContractResolver();
jsonResolverFoo.IgnoreProperty(typeof(Foo), "number2");
var serializerSettingsFoo = new JsonSerializerSettings();
serializerSettingsFoo.ContractResolver = jsonResolverFoo;
var deserializedJsonFoo = JsonConvert.DeserializeObject<List<Foo>>(Foojson, serializerSettingsFoo);

/* Resource Link: https://blog.rsuter.com/advanced-newtonsoft-json-dynamically-rename-or-ignore-properties-without-changing-the-serialized-class/ */

Comments

1

Adding to drzaus answer: You can use the DefaultContractResolver he suggested .. just in its CreateProperty use property.Ignored = true; instead of property.ShouldSerialize, then its good either when you pass the JsonSerializerSettings to the DeserializeObject function or the SerializeObject function.

3 Comments

Doesn't work for me; I also tried GetIsSpecified, and then tried to look at JsonConvert's source code and I don't actually think it's possible. Maybe substitute the property.ValueProvider with some sort of noop?
i tested it and it did work.. what happened in your case?
Nothing happened in my case. It ignored my ignoring of the property and continued to deserialize. ¯\_(ツ)_/¯
1

Alternative;

If ResponseAttribute has in model or string parameters

public class ResponseAttribute : Attribute { }

public class ModelItem
{
    [Response]
    public Guid Id { get; set; }
}

Code;

public class CustomJsonSerializer : JsonSerializerSettings
{
    public CustomJsonSerializer()
    {
        ContractResolver = new CustomContractResolver();
    }

    public CustomJsonSerializer(params string[] members)
    {
        ContractResolver = new CustomContractResolver(members);
    }

    public class CustomContractResolver : DefaultContractResolver
    {
        public string[] Members { get; set; }
        public CustomContractResolver(params string[] _members)
        {
            Members = _members;
        }

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

            if (Members?.Length > 0)
                property.ShouldSerialize = instance => { return Members.Contains(member.Name); };
            else
                property.ShouldSerialize = instance => { return member.GetCustomAttribute<ResponseAttribute>() != null; };

            return property;
        }
    }
}

Use;

return new JsonResult(model, new CustomJsonSerializer());

or

return new JsonResult(model, new CustomJsonSerializer("Id","Test","Test2"));

Comments

1

According to https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-how-to?pivots=dotnet-6-0

Any JSON properties that aren't represented in your class are ignored.

Comments

0

I ran into something similar but my class contained List<> and Dictionary<> which were populated and should not be overwritten by whatever the JSON file had. It was easier for me to load the data into a scratch object and then just pull the items I needed as opposed to any other method I could find at the time.

So for this example, something like this...

public class Foo
{
    public string string1 { get; set; }
    public string string2 { get; set; }
    public string string3 { get; set; }
}
List<Foo> foos = new List<Foo>();

List<Foo> tmp= JsonConvert.DeserializeObject<List<Foo>>(json);

foreach(Foo item in tmp)
{
    foos.string1 = tmp.string1;
    foos.string3 = tmp.string3;
}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.