为避免阻止您的服务代码,请将已知类型放入服务的 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 个数据契约在导入服务定义时在客户端和服务器之间共享,返回集合的方法在生成的客户端代理中没有得到正确的已知类型属性。也许这是设计使然。