You can solve this problem with DataContractSurrogate for deserialization, which replaces IList with List.
public class CustomDataContractSurrogate : IDataContractSurrogate { // The only function you should care about here. The rest don't do anything, just default behavior. public Type GetDataContractType(Type type) { if (type.IsGenericType && type.GetGenericTypeDefinition().Equals(typeof(ICollection<>))) { return (typeof(List<>).MakeGenericType(type.GetGenericArguments().Single())); } return type; } public object GetObjectToSerialize(object obj, Type targetType) { return obj; } public object GetDeserializedObject(object obj, Type targetType) { return obj; } public object GetCustomDataToExport(MemberInfo memberInfo, Type dataContractType) { return null; } public object GetCustomDataToExport(Type clrType, Type dataContractType) { return null; } public void GetKnownCustomDataTypes(Collection<Type> customDataTypes) { } public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData) { return null; } public CodeTypeDeclaration ProcessImportedType(CodeTypeDeclaration typeDeclaration, CodeCompileUnit compileUnit) { return typeDeclaration; } }
Basically, you just need to create an instance of the DataContractSerializer with this surrogate and use it for deserialization (it doesn't matter for serialization), for example:
var serializer = new DataContractSerializer(type, new Type[]{}, Int32.MaxValue, false, true, new CustomDataContractSurrogate());
Or any of the other constructors that accept a surrogate.
Or (as a bonus to the answer), if you work with applications defined in the /web.config application, you can define a custom behavior that creates a data serializer with the surrogate above:
public class CustomDataContractSerializerBehavior : DataContractSerializerOperationBehavior { public CustomDataContractSerializerBehavior(OperationDescription operation) : base(operation) { } public CustomDataContractSerializerBehavior(OperationDescription operation, DataContractFormatAttribute dataContractFormatAttribute) : base(operation, dataContractFormatAttribute) { } public override XmlObjectSerializer CreateSerializer(Type type, string name, string ns, IList<Type> knownTypes) { return new DataContractSerializer(type, knownTypes, Int32.MaxValue, false, true, new CustomDataContractSurrogate()); } public override XmlObjectSerializer CreateSerializer(Type type, XmlDictionaryString name, XmlDictionaryString ns, IList<Type> knownTypes) { return new DataContractSerializer(type, knownTypes, Int32.MaxValue, false, true, new CustomDataContractSurrogate()); } }
Finally you can use this behavior:
public static IMyDataServiceContract CreateService() { var factory = new ChannelFactory<IMyDataServiceContract>("MyServiceName"); SetDataContractSerializerBehavior(factory.Endpoint.Contract); return factory.CreateChannel(); } private static void SetDataContractSerializerBehavior(ContractDescription contractDescription) { foreach (OperationDescription operation in contractDescription.Operations) { ReplaceDataContractSerializerOperationBehavior(operation); } } private static void ReplaceDataContractSerializerOperationBehavior(OperationDescription description) { DataContractSerializerOperationBehavior dcsOperationBehavior = description.Behaviors.Find<DataContractSerializerOperationBehavior>(); if (dcsOperationBehavior != null) { description.Behaviors.Remove(dcsOperationBehavior); description.Behaviors.Add(new CustomDataContractSerializerBehavior(description)); } }
To exit , call the CreateService above to create a channel.