0

I have a multi-project solution. One Project is providing a DLL containing multiple classes.

One of those classes is WorkerTemplate. Two other classes inherit from it namely ExecSQLWorker and CopyWorker

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

In my WCF Service i have my Interface like that:

 public interface IPQWService
 {
     [OperationContract]
     void EnqueueWorker(WorkerTemplate[] 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?

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
tuxmania
  • 906
  • 2
  • 9
  • 28

1 Answers1

0

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. 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.

  1. Add to your WorkerTemplate class the 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

  3. You can use a 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();
    }
    
Community
  • 1
  • 1
Rabban
  • 2,451
  • 1
  • 19
  • 21
  • so although WorkerTemplate is defined in the DLL i have to redefine it completely in the WCF Service? Isn't that a bit shitty in terms of code duplication? – tuxmania Jan 04 '17 at 10:59
  • @tuxmania Yes, the `KnownTypeAttribute` has many flaws, but it is the easiest way to solve your issue. I edited my answer to show some other ways. – Rabban Jan 04 '17 at 11:29
  • i added this to ` [ServiceContract] [ServiceKnownType(typeof(ExecSQLWorker))] [ServiceKnownType(typeof(CopyWorker))] [ServiceKnownType(typeof(WorkerTemplate))] public interface IPQWService { [OperationContract] void EnqueueWorker(WorkerTemplate[] worker); }` Still i get the same error – tuxmania Jan 04 '17 at 12:14
  • @tuxmania You need to add the Attribute to your `WorkerTemplate` class, not to the interface. If you want to change the interface look at the link by point 2. – Rabban Jan 04 '17 at 12:28
  • MSDN is telling me something different. [ServiceKnownType] can also be used with only type and this has to be added to the ServiceContract that is my Interface. – tuxmania Jan 04 '17 at 12:56
  • Did you tried any of my stated solutions? All will resolve your issue. I didn't wrote anything about `ServiceKnownType`. – Rabban Jan 04 '17 at 13:04
  • I tried the 2nd solution which is adding [ServiceKnownTypes] to the ServiceConract. But it seems to have no effect – tuxmania Jan 04 '17 at 13:06
  • The linked post shows you how to use it correctly with the use of a `KnownTypesProvider` – Rabban Jan 04 '17 at 13:09
  • Exactly by using the [ServiceKnownTypes] Attribute. However it didn't work. I answer seperatly so i can use the code style again – tuxmania Jan 04 '17 at 13:12