Use base class as parameter for WCF Service(使用基类作为 WCF 服务的参数)
问题描述
我有一个多项目解决方案.一个项目正在提供一个包含多个类的 DLL.
I have a multi-project solution. One Project is providing a DLL containing multiple classes.
其中一个类是 WorkerTemplate
.另外两个类继承自它,即 ExecSQLWorker
和 CopyWorker
One of those classes is WorkerTemplate
. Two other classes inherit from it namely ExecSQLWorker
and CopyWorker
class ExecSQLWorker : WorkerTemplate {};
class CopyWorker: WorkerTemplate {};
在我的 WCF 服务中,我的界面是这样的:
In my WCF Service i have my Interface like that:
public interface IPQWService
{
[OperationContract]
void EnqueueWorker(WorkerTemplate[] worker);
}
现在在我的客户端应用程序中,WorkerTemplate[]
由 ExecSQLWorker
和 CopyWorker
对象组成.当我现在尝试调用 EnqueueWorker(worker)
方法时,我收到一条错误消息,告诉我序列化 worker 类时出现问题.
Now in my client application the WorkerTemplate[]
consists of ExecSQLWorker
and CopyWorker
objects. When i now try to call the EnqueueWorker(worker)
method i get an error telling me there is a problem serializing the worker class.
所以我猜这是因为该服务在序列化基类时确实存在问题,而是获得了继承类.但是如何轻松解决这个问题呢?
So i guess it is because the service does have problems when serializing the base class and it gets inherit classes instead. But how to fix this easily?
例外:
Unhandled Exception: System.ServiceModel.CommunicationException: There was an error while trying to serialize parameter http://tempuri.org/:worker. The InnerException message was 'Type 'DV_BII30.ExecSQLWorker' with data contract name 'ExecSQLWorker:http://schemas.datacontract.org/2004/07/DV_BII30' is not expected. Consider using a DataContractResolver if you are using DataContractSerializer or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to the serializer.'. Please see InnerException for more details. ---> System.Runtime.Serialization.SerializationException: Type 'DV_BII30.ExecSQLWorker' with data contract name 'ExecSQLWorker:http://schemas.datacontract.org/2004/07/DV_BII30' is not expected. Consider using a DataContractResolver if you are using DataContractSerializer or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to the serializer.
at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeAndVerifyType(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, Boolean verifyKnownType, RuntimeTypeHandle declaredTypeHandle, Type declaredType)
at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeWithXsiType(XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle objectTypeHandle, Type objectType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle, Type declaredType)
at System.Runtime.Serialization.XmlObjectSerializerWriteContext.InternalSerialize(XmlWriterDelegator xmlWriter, Object obj, Boolean isDeclaredType, Boolean writeXsiType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle)
at WriteArrayOfWorkerTemplateToXml(XmlWriterDelegator , Object , XmlObjectSerializerWriteContext , CollectionDataContract )
at System.Runtime.Serialization.CollectionDataContract.WriteXmlValue(XmlWriterDelegator xmlWriter, Object obj, XmlObjectSerializerWriteContext context)
at System.Runtime.Serialization.XmlObjectSerializerWriteContext.WriteDataContractValue(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle)
at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeWithoutXsiType(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle)
at System.Runtime.Serialization.DataContractSerializer.InternalWriteObjectContent(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver)
at System.Runtime.Serialization.DataContractSerializer.InternalWriteObject(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver)
at System.Runtime.Serialization.XmlObjectSerializer.WriteObjectHandleExceptions(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver)
at System.Runtime.Serialization.XmlObjectSerializer.WriteObject(XmlDictionaryWriter writer, Object graph)
at System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.SerializeParameterPart(XmlDictionaryWriter writer, PartInfo part, Object graph)
--- End of inner exception stack trace ---
Server stack trace:
at System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.SerializeParameterPart(XmlDictionaryWriter writer, PartInfo part, Object graph)
at System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.SerializeParameter(XmlDictionaryWriter writer, PartInfo part, Object graph)
at System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.SerializeParameters(XmlDictionaryWriter writer, PartInfo[] parts, Object[] parameters)
at System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.SerializeBody(XmlDictionaryWriter writer, MessageVersion version, String action, MessageDescription messageDescription, Object returnValue, Object[] parameters, Boolean isRequest)
at System.ServiceModel.Dispatcher.OperationFormatter.SerializeBodyContents(XmlDictionaryWriter writer, MessageVersion version, Object[] parameters, Object returnValue, Boolean isRequest)
at System.ServiceModel.Dispatcher.OperationFormatter.OperationFormatterMessage.OperationFormatterBodyWriter.OnWriteBodyContents(XmlDictionaryWriter writer)
at System.ServiceModel.Channels.BodyWriterMessage.OnWriteBodyContents(XmlDictionaryWriter writer)
at System.ServiceModel.Channels.Message.OnWriteMessage(XmlDictionaryWriter writer)
at System.ServiceModel.Channels.BufferedMessageWriter.WriteMessage(Message message, BufferManager bufferManager, Int32 initialOffset, Int32 maxSizeQuota)
at System.ServiceModel.Channels.TextMessageEncoderFactory.TextMessageEncoder.WriteMessage(Message message, Int32 maxMessageSize, BufferManager bufferManager, Int32 messageOffset)
at System.ServiceModel.Channels.HttpOutput.SerializeBufferedMessage(Message message, Boolean shouldRecycleBuffer)
at System.ServiceModel.Channels.HttpOutput.Send(TimeSpan timeout)
at System.ServiceModel.Channels.HttpChannelFactory`1.HttpRequestChannel.HttpChannelRequest.SendRequest(Message message, TimeSpan timeout)
at System.ServiceModel.Channels.RequestChannel.Request(Message message, TimeSpan timeout)
at System.ServiceModel.Dispatcher.RequestChannelBinder.Request(Message message, TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)
Exception rethrown at [0]:
at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
at DV_BII30.ServiceReference1.IPQWService.EnqueueWorker(WorkerTemplate[] worker)
at DV_BII30.Program.Main(String[] args) in C:TFS
obert.hartmannPCOFeaturesCDW5.0 PrototypingSourcesDTSxDataVault_Staging_CDWDV_BII30Program.cs:line 119
推荐答案
错误信息告诉你该怎么做:
The error message tells you what to do:
InnerException 消息是 'Type 'DV_BII30.ExecSQLWorker',数据合约名称为 'ExecSQLWorker:http://schemas.datacontract.org/2004/07/DV_BII30' 不是预期的.如果您正在使用 DataContractSerializer 或将任何静态未知的类型添加到已知类型列表中,请考虑使用 DataContractResolver - 例如,通过使用 KnownTypeAttribute 属性或将它们添加到传递给序列化程序的已知类型列表中.有关更多详细信息,请参阅 InnerException.---> System.Runtime.Serialization.SerializationException:键入 'DV_BII30.ExecSQLWorker',数据合同名称为 'ExecSQLWorker:http://schemas.datacontract.org/2004/07/DV_BII30' 不是预期的.如果您使用 DataContractSerializer 或将任何静态未知的类型添加到已知类型列表中,请考虑使用 DataContractResolver - 例如,通过使用 KnownTypeAttribute 属性或将它们添加到传递给序列化程序的已知类型列表中.
The InnerException message was 'Type 'DV_BII30.ExecSQLWorker' with data contract name 'ExecSQLWorker:http://schemas.datacontract.org/2004/07/DV_BII30' is not expected. Consider using a DataContractResolver if you are using DataContractSerializer or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to the serializer.'. Please see InnerException for more details. ---> System.Runtime.Serialization.SerializationException: Type 'DV_BII30.ExecSQLWorker' with data contract name 'ExecSQLWorker:http://schemas.datacontract.org/2004/07/DV_BII30' is not expected. Consider using a DataContractResolver if you are using DataContractSerializer or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to the serializer.
你有几种可能解决这个问题.
You have a couple of possibilities to solve this issue.
将
KnownTypeAttribute
[DataContract]
[KnownType(typeof(ExecSQLWorker))]
[KnownType(typeof(CopyWorker))]
public class WorkerTemplate
{
//Properties and stuff
}
如果您可以更改 IPQWService
接口,请查看此处
您可以使用 DataContractResolver
public class SharedTypeResolver : DataContractResolver
{
public override bool TryResolveType(Type dataContractType, Type declaredType, DataContractResolver knownTypeResolver, out XmlDictionaryString typeName, out XmlDictionaryString typeNamespace)
{
if (!knownTypeResolver.TryResolveType(dataContractType, declaredType, null, out typeName, out typeNamespace))
{
XmlDictionary dictionary = new XmlDictionary();
typeName = dictionary.Add(dataContractType.FullName);
typeNamespace = dictionary.Add(dataContractType.Assembly.FullName);
}
}
public override Type ResolveName(string typeName, string typeNamespace, Type declaredType, DataContractResolver knownTypeResolver)
{
return knownTypeResolver.ResolveName(typeName, typeNamespace, declaredType, null) ?? Type.GetType(typeName + ", " + typeNamespace);
}
}
解析器接受您在服务中使用的每种类型.但是您必须将解析器添加到您的客户端端点和服务器端点.像这样:
The Resolver accepts every type you use in your service. But you have to add the resolver to your Client endpoint and server endpoint. Like this:
Host = new ServiceHost(typeof(MyService));
ContractDescription cd = Host.Description.Endpoints[0].Contract;
foreach (var operation in cd.Operations)
{
operation.Behaviors.Find<DataContractSerializerOperationBehavior>()
.DataContractResolver = new SharedTypeResolver();
}
这篇关于使用基类作为 WCF 服务的参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:使用基类作为 WCF 服务的参数
基础教程推荐
- 为什么Flurl.Http DownloadFileAsync/Http客户端GetAsync需要 2022-09-30
- SSE 浮点算术是否可重现? 2022-01-01
- 有没有办法忽略 2GB 文件上传的 maxRequestLength 限制? 2022-01-01
- 将 Office 安装到 Windows 容器 (servercore:ltsc2019) 失败,错误代码为 17002 2022-01-01
- rabbitmq 的 REST API 2022-01-01
- 如何在 IDE 中获取 Xamarin Studio C# 输出? 2022-01-01
- 如何激活MC67中的红灯 2022-01-01
- c# Math.Sqrt 实现 2022-01-01
- MS Visual Studio .NET 的替代品 2022-01-01
- 将 XML 转换为通用列表 2022-01-01