Search code examples
wcfdatacontractserializerdatacontract

WCF DataContract - treating derived class as base class for serialization


I have a simple data contract:

[DataContract]
public class MyData
{
   [DataMember]
   public string AwesomeData { get; set; }
}

And service contract:

[ServiceContract]
public interface IMyDataService
{
   [OperationContract]
   MyData GetAwesomeData();
}

In the server-side assembly, I create a derived class for doing processing:

public class MyDataWithInnerds: MyData
{
   public MyDataWithInnerds(object intializationStuff)
   {
      AwesomeData = Hypermaxulate(initializationStuff);
   }
}

and the service implementation:

public class MyDataService: IMyDataService
{
  public MyData GetAwesomeData()
  {
     return new MyDataWithInnerds(HupnerRayvakManager.GetInitializationStuff());
  }
}

MyDataWithInnerds is just the functional implementation of the purely data contract MyData.

Is there anyway without decorating MyData and referencing MyDataWithInnerds to tell the serializer to serialize MyDataWithInnerds as MyData? The assembly with MyData is also given to clients. I don't want the server-side only MyDataWithInnerds to be referenced.

I don't need to de-serialize it to MyDataWithInnerds. I'm guessing I'm going to need to clone the MyDataWithInnerds instance to a MyData instance so it doesn't have any type information associated with MyDataWithInnerds, but it would be really efficient to not have to do that and just let the serializer know "I know this is a MyDataWithInnerds, but you can just treat it like the base MyData"

Thanks, Mike

EDIT

I was able to add the following to my config file on the server:

  <system.runtime.serialization>
    <dataContractSerializer>
      <declaredTypes>
        <add type="MyClientLib.MyData, MyClientLib">
          <knownType type="MyServerLib.MyDataWithInnerds, MyServerLib"/>
        </add>
      </declaredTypes>
    </dataContractSerializer>
  </system.runtime.serialization>

And this makes the serialization work properly.

It just leaves two side questions:

  1. In my JSON serialization, I end up with a "__type" member that contains the derived class type. Can I remove that?
  2. Is there a declarative way to do, on the server objects (not MyData), what I have done in configuration (adding KnownType's)?

Thanks2, Mike


Solution

  • In the end, I created a copy constructor for my base class and instead of returning the derived class (as the base class), I return new base(derived).

    [DataContract]
    public class MyData
    {
       [DataMember]
       public string AwesomeData { get; set; }
    
       public MyData(MyData obj)
       {
           AwesomeData = obj.AwesomeData;
       }
    }
    

    The service implementation then becomes:

    public class MyDataService: IMyDataService
    {
      public MyData GetAwesomeData()
      {
         MyDataWithInnerds data = 
             new MyDataWithInnerds(HupnerRayvakManager.GetInitializationStuff());
         return new MyData(data);
      }
    }
    

    In the simplistic example it looks like overkill, but in the actual application, it works out decently -- without having extra configuration and not emitting extraneous serialized data.