I have a complex object which is ISerializable and i want to serialize it into an XML document (node that i rather to not change the source code and add XML serialization attribute stuff). ISerializable works fine with BinaryFormatter, but there is no standard way to serialize it into XML or Json. The Json.NET library does support for serializing a ISerializable object into json, but there is a very small problem with that implementation, and that is the serializable constructor of class should be public in order to Json.net detect it (see this issue) and this does make Json.net unusable for my case.
Is there any other way to serialize/deserialize ISerializable object to/from xml, Json or any other plane text formats?
Json.NET does in fact support nonpublic streaming serialization constructors for ISerializable
types. For confirmation see the source code for DefaultContractResolver.CreateISerializableContract()
.
Your actual problem is that the ISerializable
type in question is also a collection, and it appears Json.NET uses an array contract in preference to a JsonISerializableContract
for such types, as shown in DefaultContractResolver.CreateContract()
:
if (typeof(IEnumerable).IsAssignableFrom(t))
{
return CreateArrayContract(objectType);
}
if (CanConvertToString(t))
{
return CreateStringContract(objectType);
}
#if !(DOTNET || PORTABLE40 || PORTABLE)
if (!IgnoreSerializableInterface && typeof(ISerializable).IsAssignableFrom(t))
{
return CreateISerializableContract(objectType);
}
#endif
To work around this problem, you can create your own custom contract resolver that reverses this logic:
public class ISerializableCollectionContractResolver : DefaultContractResolver
{
protected override JsonContract CreateContract(Type objectType)
{
var contract = base.CreateContract(objectType);
var underlyingType = Nullable.GetUnderlyingType(objectType) ?? objectType;
if (!IgnoreSerializableInterface
&& typeof(ISerializable).IsAssignableFrom(underlyingType)
&& contract is JsonArrayContract
&& !underlyingType.GetCustomAttributes<JsonContainerAttribute>().Any())
{
contract = CreateISerializableContract(objectType);
}
return contract;
}
}
Your custom collections should now be serialized through their ISerializable
interface.
You may want to cache the contract resolver for best performance.