Our WCF service has just one method:
[ServiceContract(Name = "Service", Namespace = "http://myservice/")]
[ServiceKnownType("GetServiceKnownTypes", typeof(Service))]
public interface IService {
Response Execute(Request request);
}
public class Service : IService {
public static IEnumerable<Type> GetServiceKnownTypes(ICustomAttributeProvider provider) {
return KnownTypesResolver.GetKnownTypes();
}
public Response Execute(Request request) {
return new MyResponse { Result = MyEnumHere.FirstValue };
}
}
Both the Request and Response class includes a ParameterCollection member.
[Serializable]
[CollectionDataContract(Name = "ParameterCollection", Namespace = "http://myservice/")]
[KnownType("GetKnownTypes")]
public class ParameterCollection : Dictionary<string, object> {
private static IEnumerable<Type> GetKnownTypes()
{
return KnownTypesResolver.GetKnownTypes();
}
}
Subclasses of Request and Response store their values into the ParameterCollection value bag.
I am using the KnownTypesResolver class to provide type information across all Service objects.
public static class KnownTypesResolver {
public static IEnumerable<Type> GetKnownTypes()
{
var asm = typeof(IService).Assembly;
return asm
.GetAllDerivedTypesOf<Response>() // an extension method
.Concat(new Type[] {
typeof(MyEnumHere),
typeof(MyEnumHere?),
typeof(MyClassHere),
typeof(MyClassListHere),
});
}
}
If I’m not mistaken, everything should have proper type information for proxy class generation tools to produce well-defined classes client-side.
However, whenever one of the Response subclasses (i.e. MyResponse) contains an enum value such as MyEnumHere, WCF starts complaining that the deserializer has no knowledge of the MyEnumHere value. It should have. I provided a KnownTypeAttribute for this very reason.
The client-side proxy class does have a MyEnumHere enum in the Reference.cs file; the problem is that the ParameterCollection class has no KnownTypeAttributes generated for it.
I resorted to hand-editing and including the following lines in the generated Reference.cs file:
//>
[KnownTypeAttribute(typeof(MyEnumHere))]
[KnownTypeAttribute(typeof(MyEnumHere?))]
[KnownTypeAttribute(typeof(MyClassHere))]
[KnownTypeAttribute(typeof(MyClassListHere))]
//<
public class ParameterCollection : Dictionary<string, object> { /* ... */ }
Hand-editing generated files is horrible. But this makes the clients work. What am I doing wrong? How can I define my Service objects so that the VS-proxy classes that are generated are correct from the get-go?
Thanks for your time.
WCF does not work well with
Dictionarybecause it is not interoperable. You may useArray,Listor custom collection to make sure that your data is properly serialized.Code below uses
List<ParamCollectionElement>instead ofDictionary. I also removed some redundant attributes.