WCF,接口返回类型和已知类型

发布于 2024-11-09 12:40:24 字数 1779 浏览 0 评论 0原文

我正在创建 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 消息是“类型” 带有数据合约名称的“WCFTest.Atm” 'Atm:http://schemas.datacontract.org/2004/07/WCFTest' 预计不会。考虑使用 DataContractResolver 或添加任何类型 静态未知的列表 已知类型 - 例如,通过使用 KnownTypeAttribute 属性或通过 将它们添加到已知类型列表中 传递给 DataContractSerializer。'。

非常好...那么,我认为VS的自动生成代码是垃圾。我在我的服务(以及所有相关的类和实现)中进行了以下更改:

[OperationContract]
        ICollection<Atm> GetAtms();

所以现在,我返回一个具体类型。更新服务引用后,它会创建 Atm 类的副本及其成员和内容。 调用服务后,调用成功。 我认为这是与自动生成的代码相关的一些不良行为,所以我尝试创建一个非常简单的主机/客户端应用程序。我启动了一个控制台主机,侦听某个端口,然后创建一个使用 ClientBase 类来调用服务的客户端。相同的行为...如果实现的服务返回接口类型,则会失败。如果我更改它以返回具体类型,它就可以工作。我认为我的 KnownType 属性有一些问题,我一定缺少序列化程序无法处理的东西。但我不知道是什么。

I'm creating a WCF service, and I'm having a lot of trouble with some Serialization issues. Perhaps there's just 1 way to do it, but i'd like to confirm it
Here's my sample code :

Contracts

public interface IAtm
    {
        [DataMember]
        double Latitude { get; set; }

        [DataMember]
        double Longitude { get; set; }
    }

[ServiceContract]
    public interface IAtmFinderService
    {

        [OperationContract]
        ICollection<IAtm> GetAtms();

    }

Service Implementation :

[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 } 
            };
    }
}

I added all of the KnownType and ServiceKnownType attributes because i thought that there was something missing there..
So now, i've been doing some tests. I tried creating a console app, using the "add service reference" method to make VS create automatically the proxy. This way, I get a function like

object[] GetAtms();

When trying to call it, i get this error :

The InnerException message was 'Type
'WCFTest.Atm' with data contract name
'Atm:http://schemas.datacontract.org/2004/07/WCFTest'
is not expected. Consider using a
DataContractResolver or add any types
not known statically to the list of
known types - for example, by using
the KnownTypeAttribute attribute or by
adding them to the list of known types
passed to DataContractSerializer.'.

Very nice... So then, I think that VS's autogenerated code is crap. I did the following change in my service (and all the related classes and implementations) :

[OperationContract]
        ICollection<Atm> GetAtms();

So now, i'm returning a concrete type. After updating the service reference, it creates a copy of the Atm class, with its members and stuff.
After calling the service, the call succeeds.
I thought that this was some bad behaviour related to the autogenerated code, so i tried creating a very simple host/client app. I started a console host listening on some port, then created a client that uses the ClientBase class to make a call to the service. Same behaviour... if the service is implemented returning an interface type, it fails. If i change it to return the concrete type, it works. I think that i have some problem with the KnownType attributes, i must be missing something that the serializer can't process. but i don't know what.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

樱桃奶球 2024-11-16 12:40:24

好的,我设法修复它
在我看来,问题在于,

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

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

    [OperationContract]
    ICollection<IAtm> GetAtms();

}

Ok, i managed to fix it
The problem, as I see it, was this

Since I'm returning an interface and not a concrete class, WCF doesn't know what to expect on the other end. So, it can be anything. When he gets a List, he's confused.
The correct way to do it was to add the KnownType attributes where needed.
Who needs to know those types? the service implementation, to serialize and deserialize them correctly. However, the client talks with the interface of the service, not with the implementation itself. That's why adding the KnownType attribute in the service implementation didn't work
The problem here is that interfaces don't allow KnownType attributes, but they do allow ServiceKnownType attributes. The solution to the problem was to add the expected type in the service interface contract, and voila, everything works ok and using interfaces

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

    [OperationContract]
    ICollection<IAtm> GetAtms();

}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文