类型的 WCF 问题

本文关键字:问题 WCF 类型 | 更新日期: 2023-09-27 18:18:37

当我调用 WCF Soap 服务的方法时,抛出错误并在 svlog 文件中出现错误:

键入"xxx.ActiveDirectoryService.classes.WCF.Message",数据协定名称为"Message:http://schemas.datacontract.org/2004/07/xxx.ActiveDirectoryService.classes.WCF"不是必需的。请考虑使用 DataContractResolver 或将任何静态未知的类型添加到已知类型列表中 - 例如,通过使用 KnownTypeAttribute 属性或将它们添加到传递给 DataContractSerializer 的已知类型列表中。

我试图在这里和那里使用 KnownType,但没有成功(我必须承认我不太确定我是否 100% 正确使用(。

这是我的接口/类:

[ServiceContract]
public interface IActiveDirectory
{
    [OperationContract]
    [WebGet]
    void Dummy();
    [OperationContract]
    [WebGet]
    AbstractMessage Dummy2();
    [OperationContract]
    [WebGet]
    AbstractMessage Dummy3();
    [OperationContract]
    [WebGet]
    AbstractMessage SetPassWord(string customer, string customerPassword, string userLogin, string userPassword);
}
[DataContract]
public abstract class AbstractMessage
{
    [DataMember]
    public virtual bool IsError { get; set; }
    [DataMember]
    public virtual string ErrorMessage { get; set; }
    [DataMember]
    public virtual string ReturnValue { get; set; }
}
public class Message : AbstractMessage
{
<...>
}

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
[KnownType(typeof(AbstractMessage))]
public class ActiveDirectory : IActiveDirectory
{
    public void Dummy()
    {
    }
    public AbstractMessage Dummy2()
    {
        return new AbstractMessage();
    }
    public AbstractMessage Dummy3()
    {
        return new Message();
    }
    public AbstractMessage SetPassWord(string customer, string customerPassword, string userLogin, string userPassword)
    {
    <...>
        return message; // message is of type Message
    }
}

编辑:12AM35 GMT+1

我添加了Dummy((方法。

  • 从客户端调用虚拟人工作正常。
  • 从客户端调用 Dummy2 工作正常。
  • 从客户端调用 Dummy3 会导致相同的错误。

编辑12AM39 GMT+1

进行以下更改没有帮助。

[DataContract]
[KnownType(typeof(AbstractMessage))]
public class Message : AbstractMessage
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
[KnownType(typeof(AbstractMessage))]
[KnownType(typeof(Message))]
public class ActiveDirectory : IActiveDirectory

编辑:13AM31 GMT+1

如果我将 Dummy3 返回类型设置为 Message,则在客户端代码中调用 Dummy3 是有效的。
WCF + 多态性有些奇怪...

类型的 WCF 问题

WCF 服务需要返回 DTO。 这些不能是接口,如果要返回抽象基类,则需要告诉数据协定序列化程序您实际打算返回这些类型的哪些实现。

它已经知道 AbstractMessage 类型(作为操作协定的一部分(,但是该类型的所有未在操作协定中显式声明的实现都应在已知类型中声明。

尝试添加以下内容:

[ServiceContract]
[ServiceKnownType(typeof(Message))]
public interface IActiveDirectory
{
    ...
}

在这里,您告诉数据协定序列化程序,此服务可能会返回(或期望(类型 Message 的对象作为其方法的参数。

这也应该有效:

[DataContract]
[KnownType(typeof(Message))]
public abstract class AbstractMessage
{
    ...
}

因为您要告诉数据协定序列化程序Message是已知的AbstractMessage类型

我相信您的更改不起作用,因为您在服务上使用 KnownType 而不是 ServiceKnownType,并且您尝试将已知类型应用于派生类而不是父类,这是您习惯于在语言中做的事情(消息是抽象消息(,但在 WCF 中,您必须翻转它并将派生的实现放在父类上(抽象消息具有实现消息(,这可能是限制性的。

你说:There 's something odd with WCF + Polymorphism...

相信我,最好不要认为WCF支持多语,因为它不是。 您只需返回 DTO,如果您想尝试制作这些多态性,您会遇到很多问题。 多态性是使用接口实现的,不能在 WCF 中使用接口。 如果使用抽象类,那么由于 c# 中缺少多重继承,您很快就会意识到 DTO 只能表示对象的单个视图,并且无法创建表示域模型类的多个接口的 DTO。

有关如何通过已知类型、ServiceKnownType 或配置传递已知类型知识的详细信息,请参阅此处的回答。

[KnownType(typeof(AbstractMessage))]

编译器已经发现你返回了AbstractMessage。它无法从描述中找出的是派生自AbstractMessage的实例。这些是您需要公开的类型。从 AbstractMessage 派生并返回的任何类型都需要是已知类型,这需要在 AbstractMessage 本身上声明。

[KnownType(typeof(DerivedMessage1))]
[KnownType(typeof(DerivedMessage2))]
[KnownType(typeof(DerivedMessage3))]

在您的情况下,您需要该属性来告诉数据协定序列化程序:"嘿,如您所见,我将返回一个AbstractMessage,但您不可能知道的是:实际上,这是一个Message":

[ServiceBehavior(...)]
[KnownType(typeof(Message))]
public class ActiveDirectory : IActiveDirectory
{
    public AbstractMessage Dummy3()
    {
        return new Message();
    }
}

我曾经遇到过这个问题。就我而言,据我所知,wcf 序列化程序需要非抽象类型才能正常工作。所以就我而言,从抽象类和接口切换到普通对象使它工作。