简体   繁体   English

使用基类作为WCF服务的参数

[英]Use base class as parameter for WCF Service

I have a multi-project solution. 我有一个多项目解决方案。 One Project is providing a DLL containing multiple classes. 一个项目正在提供一个包含多个类的DLL。

One of those classes is WorkerTemplate . 这些类之一是WorkerTemplate Two other classes inherit from it namely ExecSQLWorker and CopyWorker 从它继承的另外两个类是ExecSQLWorkerCopyWorker

class ExecSQLWorker : WorkerTemplate {};
class CopyWorker: WorkerTemplate {};

In my WCF Service i have my Interface like that: 在我的WCF服务中,我的界面是这样的:

 public interface IPQWService
 {
     [OperationContract]
     void EnqueueWorker(WorkerTemplate[] worker);
 }

Now in my client application the WorkerTemplate[] consists of ExecSQLWorker and CopyWorker objects. 现在在我的客户端应用程序中, WorkerTemplate[]ExecSQLWorkerCopyWorker对象组成。 When i now try to call the EnqueueWorker(worker) method i get an error telling me there is a problem serializing the worker class. 现在,当我尝试调用EnqueueWorker(worker)方法时,出现一条错误消息,告诉我序列化worker类有问题。

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? 但是如何轻松解决此问题?

edit: Exception: 编辑:例外:

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\robert.hartmann\PCO\Features\CDW5.0 Prototyping\Sources\DTSx\DataVault_Staging_CDW\DV_BII30\Program.cs:line 119

The error message tells you what to do: 错误消息告诉您该怎么做:

The InnerException message was 'Type 'DV_BII30.ExecSQLWorker' with data contract name 'ExecSQLWorker: http://schemas.datacontract.org/2004/07/DV_BII30 ' is not expected. InnerException消息是“类型'DV_BII30.ExecSQLWorker”,数据协定名称为“ ExecSQLWorker: http//schemas.datacontract.org/2004/07/DV_BII30 ”。 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.'. 如果您正在使用DataContractSerializer或将任何静态未知的类型添加到已知类型的列表中,请考虑使用DataContractResolver-例如,通过使用KnownTypeAttribute属性或将它们添加到传递给序列化程序的已知类型的列表中。 Please see InnerException for more details. 有关更多详细信息,请参见InnerException。 ---> System.Runtime.Serialization.SerializationException: Type 'DV_BII30.ExecSQLWorker' with data contract name 'ExecSQLWorker: http://schemas.datacontract.org/2004/07/DV_BII30 ' is not expected. ---> System.Runtime.Serialization.SerializationException:类型为'DV_BII30.ExecSQLWorker'且数据协定名称为'ExecSQLWorker: http : //schemas.datacontract.org/2004/07/DV_BII30 '的应用程序不是必需的。 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. 如果您正在使用DataContractSerializer或将任何不是静态已知的类型添加到已知类型的列表中,请考虑使用DataContractResolver-例如,通过使用KnownTypeAttribute属性或将它们添加到传递给序列化程序的已知类型的列表中。

You have a couple of possibilities to solve this issue. 您有两种可能性可以解决此问题。

  1. Add to your WorkerTemplate class the KnownTypeAttribute 向您的WorkerTemplate类添加KnownTypeAttribute

     [DataContract] [KnownType(typeof(ExecSQLWorker))] [KnownType(typeof(CopyWorker))] public class WorkerTemplate { //Properties and stuff } 
  2. If you can change the IPQWService interface, take a look here 如果可以更改IPQWService接口,请在此处查看

  3. You can use a DataContractResolver 您可以使用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(); } 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM