Is it possible to ignore ExpandoObject
properties, in particular those of Delegate
type, when using JsonConvert(expando, formatting, serializerSettings)
?
Essentially I'm trying to ignore all parsing of the func
property in this example expando object:
//{
// func: () => {}
//}
Action func = () => {};
dynamic expando = new ExpandoObject();
expando.func = func;
// should be empty object {}
string json = JsonConvert(expando, formatting, serializerSettings);
The first thing I tried was overriding the converter. Unfortunately this doesn't work, as I see CanConvert
called recursively for Action
-> DelegateEntry
-> some generic type -> RuntimeMethodInfo
.
private class ExpandoObjectIgnoreConverter : ExpandoObjectConverter
{
public override bool CanConvert(Type objectType)
{
if (typeof(Delegate).IsAssignableFrom(objectType))
{
return false;
}
return base.CanConvert(objectType);
}
}
A method that works is using an error handler in serialization settings and a contract resolver. When I throw the error, all further processing of the property is ignored, i.e. Action
-> . However, I'd like to do this more elegantly than throwing an exception if possible.DelegateEntry
-> some generic type -> RuntimeMethodInfo
Error handler:
serializationSettings.Error = (sender, args) =>
{
if (args.ErrorContext.Error is InvalidCastException)
{
args.ErrorContext.Handled = true;
}
}
Contract resolver:
private class ExpandoObjectContractResolver : DefaultContractResolver
{
public override JsonContract ResolveContract(Type type)
{
if (typeof(Delegate).IsAssignableFrom(type))
{
throw new InvalidCastException();
}
else
{
return base.ResolveContract(type);
}
}
}
I'm using the edge library to script nodejs from within a C# process. I'm trying to remove functions from the returned javascript objects from within C#, as they are assigned a Delegate
type that doesn't play nicely with JsonConvert
.
ExpandoObjectConverter
does not have any custom code to write an ExpandoObject
. Instead it overrides JsonConverter.CanWrite
to return false
thereby allowing the expando to be serialized generically as an IDictionary<string, object>
.
Thus you can override CanWrite
and WriteJson()
yourself to filter undesired key/value pairs before serialization:
public class FilteredExpandoObjectConverter : ExpandoObjectConverter
{
public override bool CanWrite { get { return true; } }
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var expando = (IDictionary<string, object>)value;
var dictionary = expando
.Where(p => !(p.Value is System.Delegate))
.ToDictionary(p => p.Key, p => p.Value);
serializer.Serialize(writer, dictionary);
}
}
Then use the converter in settings as follows:
var formatting = Formatting.Indented;
var serializerSettings = new JsonSerializerSettings
{
Converters = { new FilteredExpandoObjectConverter() },
};
var json = JsonConvert.SerializeObject(expando, formatting, serializerSettings);
Note this will only filter delegates values directly owned by an ExpandoObject
. If you have a collection containing some delegates, or delegate-valued members in some POCO, they will not be filtered by this code.
Sample fiddle.