WCF,接口返回类型和KnownTypes

时间:2011-05-24 09:04:03

标签: c# visual-studio wcf visual-studio-2010

我正在创建一个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属性有一些问题,我必须遗漏序列化程序无法处理的内容。但我不知道是什么。

1 个答案:

答案 0 :(得分:36)

好的,我设法解决了这个问题 正如我所看到的,这个问题就是这个

由于我正在返回一个接口而不是一个具体的类,因此WCF不知道另一端会发生什么。所以,它可以是任何东西。当他得到一个List时,他很困惑。
正确的方法是在需要的地方添加KnownType属性。
谁需要了解这些类型?服务实现,以正确地序列化和反序列化它们。但是,客户端与服务的接口进行通信,而不是与实现本身进行通信。这就是为什么在服务实现中添加KNownType属性不起作用的原因 这里的问题是,接口不允许KnownType属性,但它们允许ServiceKnownType属性。该问题的解决方案是在服务接口合同中添加预期类型,瞧,一切正常并使用接口

    [ServiceContract]
    [ServiceKnownType(typeof(Atm))]
    [ServiceKnownType(typeof(List<Atm>))]
    public interface IAtmFinderService
    {

        [OperationContract]
        ICollection<IAtm> GetAtms();

    }