具有多态数组的 WCF 客户端调用方法失败
本文关键字:客户端 调用 方法 失败 WCF 多态 数组 | 更新日期: 2023-09-27 18:31:10
我有一个具有以下(示例)接口的 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
。
我可以从带有Foo
、Bar
或Baz
对象的 WCF 客户端调用ProcessMessage()
,一切正常。但是,我不能用数组(或列表或任何其他IEnumerable
)调用ProcessMessages(...)
,因为这会失败:
尝试序列化参数时出错 http://tempuri.org/:messages。内部异常消息是"类型 具有数据协定名称的"X.X.Foo" "Foo:http://schemas.datacontract.org/2004/07/X.X"不是预期的。 考虑使用 DataContract Resolver 或添加任何未知的类型 静态到已知类型的列表 - 例如,通过使用 已知类型属性或将它们添加到已知列表中 传递给 DataContractSerializer 的类型。 请参阅内部异常 了解更多详情。
当我查看生成的客户端代码时,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
s 添加到 ProcessMessages
方法中时,我使用包含 Foo
的数组从客户端调用它,Bar
并Baz
它工作正常。
如何让Visual Studio在第二种方法上生成这些属性?我的IMyInterface
错了吗?我是否在错误的位置添加了[ServiceKnownType(typeof(...))]
?我哪里做错了?
编辑也许,我应该提到Message
类位于一个"外部"程序集中(幸运的是,我可以控制它),我将其打包在 Nuget 包中,而 Nuget 包又在 WCF 服务和客户端中引用了"重用类型..."为此程序集启用选项。
由于您的类型位于不同的程序集中,并且/或很难修改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
属性添加到Message
类中:
[KnownType(typeof(Foo))]
[KnownType(typeof(Bar))]
[KnownType(typeof(Baz))]
public abstract class Message
那么你就不必对你的客户做任何特别的事情了。
此外,我能够重现您的行为的唯一方法是将Message
放在其自己的程序集中,从我的客户端和 WCF 库项目中引用该程序集,并使用"在引用的程序集中重用类型"复选框。如果类都是在客户端生成的,而不是一些被引用和一些生成,它的工作方式要简单得多,因为它在Message
上生成所有KnownType
属性。