If you don't control the source code, you can use a custom ContractResolver
to inject a "ShouldSerialize" method for the problematic property during serialization. You can have that method always return false, or optionally, implement some logic which will detect the situations where the property will throw and return false only in that case.
For example, let's say that your class looks like this:
class Problematic
{
public int Id { get; set; }
public string Name { get; set; }
public object Offender
{
get { throw new NullReferenceException(); }
}
}
Clearly, if we try to serialize the above, it will not work because the Offender
property will always throw an exception when the serializer tries to access it. Since we know the class and property name that causes the problem, we can write a custom ContractResolver (derived from the DefaultContractResolver) to suppress the serialization of that specific member.
class CustomResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member,
MemberSerialization memberSerialization)
{
JsonProperty property = base.CreateProperty(member, memberSerialization);
if (property.DeclaringType == typeof(Problematic) &&
property.PropertyName == "Offender")
{
property.ShouldSerialize = instanceOfProblematic => false;
}
return property;
}
}
Here's a demo showing how to use it:
class Program
{
static void Main(string[] args)
{
Problematic obj = new Problematic
{
Id = 1,
Name = "Foo"
};
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.ContractResolver = new CustomResolver();
string json = JsonConvert.SerializeObject(obj, settings);
Console.WriteLine(json);
}
}
Output:
{"Id":1,"Name":"Foo"}
A more generic solution
In your comments you indicated that you have many kinds of objects that might throw an exception when any of the properties are accessed. To that end, we need something more generic. Here is a resolver that might work for that case, but you'll need to test it extensively in your own environment. It does not depend on any particular class or property name, but creates a ShouldSerialize predicate for every property that comes its way. In that predicate it uses reflection to get the value of the property inside a try/catch; if successful it returns true, otherwise false.
class CustomResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty property = base.CreateProperty(member, memberSerialization);
property.ShouldSerialize = instance =>
{
try
{
PropertyInfo prop = (PropertyInfo)member;
if (prop.CanRead)
{
prop.GetValue(instance, null);
return true;
}
}
catch
{
}
return false;
};
return property;
}
}
Here is a demo:
class Program
{
static void Main(string[] args)
{
List<MightThrow> list = new List<MightThrow>
{
new MightThrow { Flags = ThrowFlags.None, Name = "none throw" },
new MightThrow { Flags = ThrowFlags.A, Name = "A throws" },
new MightThrow { Flags = ThrowFlags.B, Name = "B throws" },
new MightThrow { Flags = ThrowFlags.Both, Name = "both throw" },
};
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.ContractResolver = new CustomResolver();
settings.Formatting = Formatting.Indented;
string json = JsonConvert.SerializeObject(list, settings);
Console.WriteLine(json);
}
}
[Flags]
enum ThrowFlags
{
None = 0,
A = 1,
B = 2,
Both = 3
}
class MightThrow
{
public string Name { get; set; }
public ThrowFlags Flags { get; set; }
public string A
{
get
{
if ((Flags & ThrowFlags.A) == ThrowFlags.A)
throw new Exception();
return "a";
}
}
public string B
{
get
{
if ((Flags & ThrowFlags.B) == ThrowFlags.B)
throw new Exception();
return "b";
}
}
}
Output:
[
{
"Name": "none throw",
"Flags": 0,
"A": "a",
"B": "b"
},
{
"Name": "A throws",
"Flags": 1,
"B": "b"
},
{
"Name": "B throws",
"Flags": 2,
"A": "a"
},
{
"Name": "both throw",
"Flags": 3
}
]