In yeterday’s post, I mentioned that I would give the IDataContractSurrogate
a try to solve this issue. And guess what? Problem solved! Mine anyway, I’m not sure if it will help in all cases, but certainly for this one about arrays.
I started with a pass-through/noop implementation just to see if I could hook into the serialization process hoping to get some more insight. What I noticed was that GetObjectToSerialize
got called several times before the exception was thrown. In the second run, I kept track of the parameter values and found out that I overlooked an IList<T>
property somewhere deep in the object graph of the data contract. Since the property value was deserialized after retrieval over the wire it was now, of course, just a simple array…
Microsoft proposed to work around the issue by putting the data contract assembly in the GAC, however, there’s a much simpler solution: modify your object while it is being serialized.
public object GetObjectToSerialize(object obj, Type targetType) { if (obj is Array && targetType.IsGenericType && targetType.GetGenericTypeDefinition() == typeof(IList<>)) { var typeArg = targetType.GetGenericArguments()[0]; // typeof(T) var type = typeof(List<>).MakeGenericType(typeArg); // typeof(List<T>) return Activator.CreateInstance(type, obj); // new List<T>(IEnumerable<T>) } return obj; }
Put this in your IDataContractSurrogate
implementation, pass it to the constructor of your serializer and you should be good to go. Every time the serializer is about to serialize an array (T[]
) the surrogate will give it a wrapper (List<T>
) instead.
The funny thing about all this is that it is not the first time I had to implement an IDataContractSurrogate
, but for completely different reasons. The fact that my original unit test worked and that the bug was only triggered when running in IIS (or Cassini) and that putting the assembly in the GAC solved it got me so confused, that I only though about going the surrogate way later that day. I still wonder why putting the assembly in the GAC, solves the problem, though. And what’s got LoaderOptimization to do with it? The CLR moves in mysterious ways, I suppose, at least sometimes…
Image may be NSFW.
Clik here to view.

Clik here to view.
