我正在创建一个WCF服务,我遇到了一些序列化问题。也许只有一种方法可以做到,但我想确认一下 这是我的示例代码:
合同
public interface IAtm
{
[DataMember]
double Latitude { get; set; }
[DataMember]
double Longitude { get; set; }
}
[ServiceContract]
public interface IAtmFinderService
{
[OperationContract]
ICollection<IAtm> GetAtms();
}
服务实施:
[KnownType(typeof(Atm))]
[KnownType(typeof(List<Atm>))]
[ServiceKnownType(typeof(Atm))]
[ServiceKnownType(typeof(List<Atm>))]
public class AtmFinderService : IAtmFinderService
{
public ICollection<IAtm> GetAtms()
{
return new List<IAtm>()
{
new Atm() { Latitude = 1, Longitude = 1 },
new Atm() { Latitude = 2, Longitude = 2 }
};
}
}
我添加了所有的KnownType和ServiceKnownType属性,因为我认为那里缺少了一些东西.. 所以现在,我一直在做一些测试。我尝试使用“添加服务引用”方法创建一个控制台应用程序,以使VS自动创建代理。这样,我得到了一个像
这样的函数object[] GetAtms();
尝试调用时,我收到此错误:
InnerException消息是'Type 带有数据合同名称的'WCFTest.Atm' '大气压:HTTP://schemas.datacontract.org/2004/07/WCFTest' 不是预期的。考虑使用 DataContractResolver或添加任何类型 静态地不知道列表 已知类型 - 例如,通过使用 KnownTypeAttribute属性或 将它们添加到已知类型列表中 传递给DataContractSerializer。'。
非常好......那么,我认为VS的自动生成代码就是垃圾。我在我的服务(以及所有相关的类和实现)中做了以下更改:
[OperationContract]
ICollection<Atm> GetAtms();
所以现在,我正在返回一个具体的类型。更新服务引用后,它会创建Atm类的副本及其成员和内容。 呼叫服务后,呼叫成功。 我认为这是与自动生成的代码相关的一些不良行为,所以我尝试创建一个非常简单的主机/客户端应用程序。我启动了一个控制台主机侦听某个端口,然后创建了一个使用ClientBase类来调用该服务的客户端。相同的行为...如果服务实现返回接口类型,则失败。如果我改变它以返回具体类型,它可以工作。我认为我对KnownType属性有一些问题,我必须遗漏序列化程序无法处理的内容。但我不知道是什么。
答案 0 :(得分:36)
好的,我设法解决了这个问题 正如我所看到的,这个问题就是这个
由于我正在返回一个接口而不是一个具体的类,因此WCF不知道另一端会发生什么。所以,它可以是任何东西。当他得到一个List时,他很困惑。
正确的方法是在需要的地方添加KnownType属性。
谁需要了解这些类型?服务实现,以正确地序列化和反序列化它们。但是,客户端与服务的接口进行通信,而不是与实现本身进行通信。这就是为什么在服务实现中添加KNownType属性不起作用的原因
这里的问题是,接口不允许KnownType属性,但它们允许ServiceKnownType属性。该问题的解决方案是在服务接口合同中添加预期类型,瞧,一切正常并使用接口
[ServiceContract]
[ServiceKnownType(typeof(Atm))]
[ServiceKnownType(typeof(List<Atm>))]
public interface IAtmFinderService
{
[OperationContract]
ICollection<IAtm> GetAtms();
}