我们的WCF服务只有一种方法:
[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 };
}
}
Request
和Response
类都包含ParameterCollection
成员。
[Serializable]
[CollectionDataContract(Name = "ParameterCollection", Namespace = "http://myservice/")]
[KnownType("GetKnownTypes")]
public class ParameterCollection : Dictionary<string, object> {
private static IEnumerable<Type> GetKnownTypes()
{
return KnownTypesResolver.GetKnownTypes();
}
}
Request
和Response
的子类将其值存储到ParameterCollection值包中。
我使用KnownTypesResolver类在所有服务对象中提供类型信息。
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),
});
}
}
如果我没有弄错的话,一切都应该有代理类生成工具的正确类型信息,以便在客户端生成定义良好的类。
但是,只要其中一个Response
子类(即MyResponse
)包含枚举值(例如MyEnumHere
),WCF就会开始抱怨反序列化器不知道MyEnumHere值。应该有。出于这个原因,我提供了KnownTypeAttribute
。
客户端代理类在Reference.cs文件中有一个MyEnumHere
枚举;问题是ParameterCollection
类没有生成KnownTypeAttribute
。
我使用手工编辑并在生成的Reference.cs文件中包含以下行:
//>
[KnownTypeAttribute(typeof(MyEnumHere))]
[KnownTypeAttribute(typeof(MyEnumHere?))]
[KnownTypeAttribute(typeof(MyClassHere))]
[KnownTypeAttribute(typeof(MyClassListHere))]
//<
public class ParameterCollection : Dictionary<string, object> { /* ... */ }
手动编辑生成的文件非常糟糕。但这使客户工作。我究竟做错了什么?如何定义我的服务对象,以便从一开始就生成的VS代理类是正确的?
感谢您的时间。
答案 0 :(得分:1)
WCF与Dictionary
不兼容,因为它不可互操作。您可以使用Array
,List
或自定义集合来确保您的数据已正确序列化。
以下代码使用List<ParamCollectionElement>
代替Dictionary
。我还删除了一些冗余属性。
[DataContract]
public class Request
{
[DataMember]
public ParameterCollection ParameterCollection { get; set; }
}
[DataContract]
public class Response
{
[DataMember]
public ParameterCollection ParameterCollection { get; set; }
}
[DataContract]
public class MyResponse : Response
{
[DataMember]
public MyEnumHere Result { get; set; }
}
public class ParamCollectionElement
{
public string Key { get; set; }
public object Value { get; set; }
}
[CollectionDataContract(Name = "ParameterCollection")]
public class ParameterCollection : List<ParamCollectionElement>
{
}
public static class KnownTypesResolver
{
public static IEnumerable<Type> GetKnownTypes()
{
return
new Type[] {
typeof(MyEnumHere),
typeof(MyEnumHere?),
typeof(Request),
typeof(Response),
typeof(MyResponse)
};
}
}
[DataContract]
public enum MyEnumHere
{
[EnumMember]
FirstValue,
[EnumMember]
SecondValue
}
[ServiceKnownType("GetServiceKnownTypes", typeof(Service))]
[ServiceContract(Name = "Service")]
public interface IService
{
[OperationContract]
Response Execute(Request request);
}
public class Service : IService
{
public static IEnumerable<Type> GetServiceKnownTypes(ICustomAttributeProvider provider)
{
return KnownTypesResolver.GetKnownTypes();
}
public Response Execute(Request request)
{
var result = new MyResponse
{
Result = MyEnumHere.FirstValue,
ParameterCollection = new ParameterCollection()
};
result.ParameterCollection.Add(new ParamCollectionElement {Key = "one", Value = MyEnumHere.FirstValue});
result.ParameterCollection.Add(new ParamCollectionElement { Key = "two", Value = new Response() });
return result;
}
}
答案 1 :(得分:0)
确保您的枚举上有[DataContract]
,并且每个枚举成员都有[EnumMember]
:
[DataContract]
public enum MyEnumHere
{
[EnumMember]
SomeValue,
[EnumMember]
OtherValue,
[EnumMember]
OneMoreValue
}
这应该导致在客户端中构建proxy-enum(及其成员值),而无需手动更改Reference.cs文件。