有认识ServiceKnownTypes问题WCF客户端?
-
27-09-2019 - |
题
我怎么会告诉WCF服务传递数据时使用何种KnownTypes返回给客户端?
我知道我可以使用[ServiceKnownType]
属性,这使得从WCF测试服务器的服务调用运行正常,但是它仍然从客户端失败。我失去了一些东西在这里?
[OperationContract]
[ServiceKnownType(typeof(SubClassA))]
[ServiceKnownType(typeof(SubClassB))]
BaseClassZ GetObject();
从客户端错误信息是:
{“元素 'http://schemas.datacontract.org/2004/07/BaseClassZ' 包含来自映射到类型数据 名字 'http://schemas.datacontract.org/2004/07/SubClassA'。 解串器却毫不知情 任何类型映射到此名称。 考虑使用DataContractResolver 或添加了对应于类型 “SubClassA”到已知类型的列表 - 例如,通过使用KnownTypeAttribute属性或由 将它添加到已知类型的列表 传递给DataContractSerializer的。“}
序列化/反序列化使用的DataContractSerializer和KnownTypes的列表WCF服务器上的对象工作正常。
更新:看来我可以让客户端读取的对象是否正确我添加KnownType属性的基类,但我仍然在寻找一种方式解决这个,如果可能的,因为基类用于很多项目,我不希望有修改的基类我随时添加新项目KnownType属性。
[DataContract]
[KnownType(typeof(SubClassA))]
[KnownType(typeof(SubClassB))]
public class BaseClassZ
{
...
}
解决方案
要避免阻止服务代码把已知类型到服务的web.config中:
<system.runtime.serialization>
<dataContractSerializer>
<declaredTypes>
<add type="SomeNs.BaseClassZ, SomeAssembly">
<knownType type="SomeNs.SubClassA, SomeAssembly" />
<knownType type="SomeNs.SubClassB, SomeAssembly" />
</add>
</declaredTypes>
</dataContractSerializer>
</system.runtime.serialization>
如果你想通过代码来做到这一点,你需要使用这个属性的服务接口,而不是操作方法,但我宁愿声明方法:
[ServiceContract]
[ServiceKnownType(typeof(SubClassA))]
[ServiceKnownType(typeof(SubClassB))]
public interface IFoo
{
[OperationContract]
BaseClassZ GetObject();
}
更新:
我已经提出了一个示例项目说明配置已知类型使用的web.config这是我的优选的方法。和另一个示例项目展示第二种方法。
更新2:
与Silverlight应用程序客户端,我们注意到以下定义看你更新的代码之后:
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(ConfigurationName="ServiceReference1.IService1")]
public interface IService1 {
[System.ServiceModel.OperationContractAttribute(AsyncPattern=true, Action="http://tempuri.org/IService1/GetMany", ReplyAction="http://tempuri.org/IService1/GetManyResponse")]
System.IAsyncResult BeginGetMany(System.AsyncCallback callback, object asyncState);
System.Collections.ObjectModel.ObservableCollection<MyCommonLib.BaseClassZ> EndGetMany(System.IAsyncResult result);
[System.ServiceModel.OperationContractAttribute(AsyncPattern=true, Action="http://tempuri.org/IService1/GetSingle", ReplyAction="http://tempuri.org/IService1/GetSingleResponse")]
[System.ServiceModel.ServiceKnownTypeAttribute(typeof(MyCommonLib.SubClassA))]
[System.ServiceModel.ServiceKnownTypeAttribute(typeof(MyCommonLib.SubClassB))]
System.IAsyncResult BeginGetSingle(System.AsyncCallback callback, object asyncState);
MyCommonLib.BaseClassZ EndGetSingle(System.IAsyncResult result);
}
通知的BeginGetSingle
方法如何包含已知类型属性而BeginGetMany
方法没有。事实上,那些属性应该被放置在服务定义,使得类看起来像这样。
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(ConfigurationName="ServiceReference1.IService1")]
[System.ServiceModel.ServiceKnownTypeAttribute(typeof(MyCommonLib.SubClassA))]
[System.ServiceModel.ServiceKnownTypeAttribute(typeof(MyCommonLib.SubClassB))]
public interface IService1
{
[System.ServiceModel.OperationContractAttribute(AsyncPattern=true, Action="http://tempuri.org/IService1/GetMany", ReplyAction="http://tempuri.org/IService1/GetManyResponse")]
System.IAsyncResult BeginGetMany(System.AsyncCallback callback, object asyncState);
System.Collections.ObjectModel.ObservableCollection<MyCommonLib.BaseClassZ> EndGetMany(System.IAsyncResult result);
[System.ServiceModel.OperationContractAttribute(AsyncPattern=true, Action="http://tempuri.org/IService1/GetSingle", ReplyAction="http://tempuri.org/IService1/GetSingleResponse")]
System.IAsyncResult BeginGetSingle(System.AsyncCallback callback, object asyncState);
MyCommonLib.BaseClassZ EndGetSingle(System.IAsyncResult result);
}
由于这是一个自动生成的类可以有在 SLsvcUtil.exe一个错误和 svcutil.exe
,因为它表现出相同的行为。把已知类型的属性对他们的正确的地方解决了这个问题。问题是,这个类是通过工具自动生成的,如果你尝试从WSDL重新生成它会搞砸一次。
如此看来,如果你有下列服务定义:
[ServiceContract]
[ServiceKnownType(typeof(SubClassA))]
[ServiceKnownType(typeof(SubClassB))]
public interface IService1
{
[OperationContract]
BaseClassZ[] GetMany();
[OperationContract]
BaseClassZ GetSingle();
}
和这里使用的3个数据合同的客户端和服务器之间导入的服务,返回集合没有得到在所生成的客户端代理的正确已知类型属性的方法的定义时共享。也许这是由设计。
其他提示
我花了几个小时今天什么,最好能告诉我,是完全一样的问题。对于我的解决方案是从■设计的ServiceModelEx库使用AddGenericResolver方法。
注意:需要.NET 4.0,因为它使用 DataContractResolver
您可以找到它的■设计下载页面。
所有我曾在我的情况需要做的就是添加以下代码行:
Client.AddGenericResolver( typeof ( K2Source ) );
我希望这可以帮助有别人了节约几个小时!
您可以在书中找到更多信息“编程WCF服务:掌握WCF和在Azure AppFabric的服务总线”,由朱瓦尔·洛
有另一种方法来做到这一点。而不是使用“添加服务引用”你的代码的代理类。这是一个多一点的编码最初但给你一个更稳定和可靠的解决方案。我们已经发现,这节省了我们的时间,从长远来看。
请参阅: http://www.dnrtv.com/default.aspx?showNum= 122
请注意:如果您在服务器端和客户端的控制这仅适用