我有一个带有以下(示例)接口的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()
,Foo
或Bar
对象从WCF客户端调用Baz
,一切正常。但是,我无法使用数组(或列表或任何其他ProcessMessages(...)
)调用IEnumerable
,因为这会失败:
尝试序列化参数时出错 http://tempuri.org/:messages。 InnerException消息是'Type 带有数据合同名称的'X.X.Foo' 'Foo:http://schemas.datacontract.org/2004/07/X.X'不是预料之中的。 考虑使用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);
我注意到ServiceKnownTypeAttribute
已添加到ProcessMessage
但未添加到ProcessMessages
。当我手动将同一组ServiceKnownTypeAttribute
添加到ProcessMessages
方法时,我从客户端使用包含Foo
,Bar
和{{1}的数组调用它它工作正常。
如何让Visual Studio在第二种方法上生成这些属性?我的Baz
错了吗?我是否将IMyInterface
添加到了错误的位置?我哪里出错了?
修改
我应该提一下,[ServiceKnownType(typeof(...))]
类是在一个“外部”程序集中(我可以控制,幸运的是),它打包在一个Nuget包中,而后者又在WCF服务和客户端中引用为此程序集启用了“重用类型...”选项。
答案 0 :(得分: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
{
}
}
(我知道你似乎在告诉它显而易见,但它确实有效。)
如果Message
,Foo
,Bar
和Baz
位于同一个程序集中,您只需将KnownType
属性添加到{{1 class:
Message
然后你就不必为你的客户做任何特别的事了。
此外,我能够重现您的行为的唯一方法是将[KnownType(typeof(Foo))]
[KnownType(typeof(Bar))]
[KnownType(typeof(Baz))]
public abstract class Message
放在自己的程序集中,从我的客户端和WCF库项目引用它,并使用“在引用的程序集中重用类型”复选框。如果这些类都是在客户端生成的,而不是一些被引用而一些是生成的,那么它的工作要简单得多,因为它会在Message
上生成所有KnownType
属性。