3

我有一个带有以下(示例)接口的 WCF 服务:

[ServiceContract]
[ServiceKnownType(typeof(Foo))]
[ServiceKnownType(typeof(Bar))]
[ServiceKnownType(typeof(Baz))]
public interface IMyInterface
{
    [OperationContract]
    void ProcessMessage(Message message);

    [OperationContract]
    void ProcessMessages(IEnumerable<Message> messages);
}

Foo,Bar并且Baz都是 的一种Message

我可以使用,或对象ProcessMessage()从 WCF 客户端调用,一切正常。但是,我不能使用数组(或列表或任何其他)调用,因为这将失败:FooBarBazProcessMessages(...)IEnumerable

尝试序列化参数 http://tempuri.org/:messages时出错。InnerException 消息是 'Type 'XXFoo' ,数据合同名称为 'Foo: http://schemas.datacontract.org/2004/07/XX ' 不是预期的。考虑使用 DataContractResolver 或将任何静态未知的类型添加到已知类型列表中 - 例如,通过使用 KnownTypeAttribute 属性或将它们添加到传递给 DataContractSerializer 的已知类型列表中。有关更多详细信息,请参阅 InnerException。

当我查看生成的客户端代码时reference.cs,我看到:

...
[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IMyInterface/ProcessMessage", ReplyAction="http://tempuri.org/IMyInterface/ProcessMessageResponse")]
[System.ServiceModel.ServiceKnownTypeAttribute(typeof(X.X.Foo))]
[System.ServiceModel.ServiceKnownTypeAttribute(typeof(X.X.Bar))]
[System.ServiceModel.ServiceKnownTypeAttribute(typeof(X.X.Baz))]
void ProcessMessage(X.X.Message message);

...
[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IMyInterface/ProcessMessages", ReplyAction="http://tempuri.org/IMyInterface/ProcessMessagesResponse")]
void ProcessMessages(X.X.Message[] messages);

我注意到ServiceKnownTypeAttributes 被添加到ProcessMessage但不是ProcessMessages. 当我手动将同一组ServiceKnownTypeAttributes 添加到方法中并ProcessMessages使用包含 a 的数组从客户端调用它时Foo,它工作正常。BarBaz

如何让 Visual Studio 在第二种方法中也生成这些属性?我IMyInterface错了吗?我[ServiceKnownType(typeof(...))]在错误的地方添加了吗?我哪里做错了?

编辑 我也许应该提到Message该类位于“外部”程序集(幸运的是,我可以控制)中,我将其打包在 Nuget 包中,而该程序集又在 WCF 服务和客户端中通过“重用”来引用类型...”为此程序集启用了选项。

4

1 回答 1

2

由于您的类型位于不同的程序集中,并且/或者很难修改Message,因此您可以将其放入客户端程序集中以使其工作:

namespace X.X
{
    [KnownType(typeof(Foo))]
    public partial class Foo
    {
    }
    [KnownType(typeof(Bar))]
    public partial class Bar
    {
    }
    [KnownType(typeof(Baz))]
    public partial class Baz
    {
    }
}

(我知道你说的似乎很明显,但它确实有效。)

如果MessageFooBarBaz位于同一个程序集中,您只需将KnownType属性添加到您的Message类:

[KnownType(typeof(Foo))]
[KnownType(typeof(Bar))]
[KnownType(typeof(Baz))]
public abstract class Message

这样您就不必为您的客户做任何特别的事情。

此外,我能够重现您的行为的唯一方法是放入Message它自己的程序集,从我的客户端和 WCF 库项目中引用它,并使用“在引用的程序集中重用类型”复选框。如果类都是在客户端生成的,而不是一些被引用和一些生成,那么它的工作会更简单,因为它会KnownTypeMessage.

于 2013-09-12T18:50:57.780 回答