views:

386

answers:

4

I'm trying to take a datacontract object that I received on the server, do some manipulation on it and then return an upcasted version of it however it doesn't seem to be working. I can get it to work by using the KnownType or ServiceKnownType attributes, but I don't want to roundtrip all of the data. Below is an example:

[DataContract]
public class MyBaseObject
{
    [DataMember]
    public int Id { get; set; }
}

[DataContract]
public class MyDerivedObject : MyBaseObject
{
    [DataMember]
    public string Name { get; set; }
}


[ServiceContract(Namespace = "http://My.Web.Service")]
public interface IServiceProvider
{
    [OperationContract]
    List<MyBaseObject> SaveMyObjects(List<MyDerivedObject> myDerivedObjects);
}

public class ServiceProvider : IServiceProvider
{
    public List<MyBaseObject> SaveMyObjects(List<MyDerivedObject> myDerivedObjects)
    {
        ... do some work ...

        myDerivedObjects[0].Id = 123;
        myDerivedObjects[1].Id = 456;
        myDerivedObjects[2].Id = 789;

        ... do some work ...

        return myDerivedObjects.Cast<MyBaseObject>().ToList();
    }
}

Anybody have any ideas how to get this to work without having to recreate new objects or using the KnownType attributes?

A: 

I think that your problem is that you are trying to send over a generic list.

It will work if you encapsulate the list in an object. That is create an object with a single public property which is the generic list.

You also need to make sure that all classes that are not used directly in the contract are marked as serializable.

Shiraz Bhaiji
The IList sends just fine. It's when I try to upcast the object that doesn't work. I don't want to round-trip all the data.
Jarred Froman
You could try using custom mapping code, or interfaces.
Shiraz Bhaiji
A: 

If you want to return the derived objects then there will always be a round trip because the client and the service are separate. In order for the client to update its own list of MyBaseObjects it has to deserialize the list of MyDerivedObjects that came from the server.

The use of KnownType and/or ServiceKnownType is needed because this leads to the addition of that type information into WSDL, which is in turn used by the client to deserialize the messages to the correct type.

For starters, a useful tool for testing the scenario you've described: http://www.wcfstorm.com

Neat utility! :) I'll have to give it a try. Regarding the upcasting, if I instantiate the base object and set the values, I can send it up just fine, however, I'd like to avoid the extra work and just upcast the derived object. From the looks of it, this isn't possible.
Jarred Froman
A: 

You might try creating a DataContractSurrogate (IDataContractSurrogate) and returning your base type for the call to GetDataContractType. I'm not really sure that's how it was intended to be used so you still may be better of with "the extra work", but maybe I don't understand the scope of that extra work.

nedruod
A: 

One of the problems with WCF (and .net remoting) is that it they tries to make “message passing” look like method calls.

This fall down when you try to use too many “oop” type designs.

The fact that the messages are represented by .net classes, does not make all of their behaviour like .net class.

See this, and this, for more on the problem of Leaking Abstraction.

So you need to start thinking about message passing not object when designing your WCF interfaces, or you will hit lots of problems like this.

Ian Ringrose