tags:

views:

4008

answers:

6

I have a service contract that defines a method with a parameter of type System.Object (xs:anyType in the WSDL). I want to be able to pass simple types as well as complex types in this parameter. Simple types work fine, but when I try to pass a complex type that is defined in my WSDL, I get this error:

Element 'http://tempuri.org/:value' contains data of the 'http://schemas.datacontract.org/2004/07/MyNamespace:MyClass' data contract. The deserializer has no knowledge of any type that maps to this contract. Add the type corresponding to 'MyClass' to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding it to the list of known types passed to DataContractSerializer.

Adding it as a known type doesn't help because it's already in my WSDL. How can I pass an object of a complex type via an "xs:anyType" parameter?

More info:

I believe this works when using NetDataContract, but I can't use that because my client is Silverlight.

I have seen references to complex types explicitly extending xs:anyType, but I have no idea how to make WCF generate a WSDL that does that, and I have no idea whether or not it would even help.

Thanks

+2  A: 

The NetDataContract works because the NetDataContractSerializer includes type information.

The KnownType attribute instructs the DataContractSerializer how to deserialize the message. Being implementation specific, this is information over-and-above that defined by the public contract and doesn't belong in the WSDL.

You're never going to be able to pass any-old data type because the deserializer needs to identify the appropriate type and create an instance.

You may be able to derive your known types at runtime rather than having them hard-coded in the DataContract. Take a look here for a sample.

Steve Morgan
A: 

Try use data contract Surrogates to map unsupported object that is dot net specific or not interoperable types. See MSDN

codemeit
A: 

I have tried adding the ServiceKnownType attribute, specifying the type that I am trying to pass, but I still get the same error. I have also tried adding the KnownType attribute to my data contract (which seemed silly because it was the same type as the data contract). I would guess that adding them at runtime won't help if adding them at compile time doesn't help.

If I were extending another complex type, it seems to me that I would want to add the KnownType attribute to that base type. But since my base type is Object, I don't see any way to do this.

As for Surrogates, it seems to me that these are used for wrapping types that don't have a contract defined. In my case however, I do have the contract defined.

dcstraw
+1  A: 

I hope this would help. I saw a colleague of mine using this code to send complicated data types and to me this is pretty simple. This was used with basicHttpBinding and it works pretty well with MOSS BDC as well as other applications which use the basic binding.

  1. Create a data contract based on a generic class
  2. Use the data contract when the information needs to be sent

    [DataContract(Namespace = "http://Service.DataContracts", Name = "ServiceDataContractBase")] public class ServiceDataContract {

    public ServiceDataContract() { }
    
    
    public ServiceDataContract(TValueType Value)
    {
        this.m_objValue = Value;
    }
    
    
    private TValueType m_objValue;
    
    
    [DataMember(IsRequired = true, Name = "Value", Order = 1)]
    public TValueType Value
    {
        get { return m_objValue; }
        set { m_objValue = value; }
    }
    

    }

Use this data contract where ever it is needed in the WCF functions that return the complicated data type. For example:

public ServiceDataContract<string[]> GetStrings()
{
    string[] temp = new string[10];
    return new ServiceDataContract<string[]>(temp);
}

Update: ServiceDataContract is generic class is using TValueType. It is not appearing because of something wrong with the rendering of the HTML.

Syed Sajid Nizami
Thanks for the reply. However this implementation still requires specifying the type in the service contract (or am I missing something?). I want to be able to pass a non-specific type that could either be a simple type or one of my data contract types, using the same service operation.
dcstraw
A: 

For now I have worked around this by creating a new data contract type that can wrap either another data contract type or a simple type. Instead of passing type Object, now I pass this wrapper class. This works OK, but I'd still like to know if there is a solution to the original issue.

dcstraw
A: 

I have solved this problem by using the ServiceKnownType attribute. I simply add my complex type as a service known type on my service contract, and the error goes away. I'm not sure why this didn't work last time I tried it.

It doesn't appear to affect the WSDL in any way, so I suspect that the serialized stream must have some difference that informs the deserializer that the object can be deserialized using my type.

dcstraw