6

当我调用我的 WCF Soap 服务的方法时,会引发错误,并且 svlog 文件中会出现错误:

不应使用数据合同名称“消息:http: //schemas.datacontract.org/2004/07/xxx.ActiveDirectoryService.classes.WCF ”键入“xxx.ActiveDirectoryService.classes.WCF.Message” 。考虑使用 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() 方法。

  • 从客户端调用 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 + 多态性有些奇怪......

4

3 回答 3

4

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

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

尝试添加这个:

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

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

这也应该有效:

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

因为您想告诉数据合同序列化程序这Message是一种已知类型的AbstractMessage

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

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

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

有关如何通过KnownTypesServiceKnownTypes或配置传递已知类型知识的详细信息,请参阅我的答案。

于 2013-06-17T11:39:00.253 回答
3
[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();
    }
}
于 2013-06-17T10:35:17.757 回答
0

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

于 2013-06-17T10:17:37.463 回答