CommonGenius.com

As the WCF documentation explains repeatedly, one of the major differences between WCF and remoting is that remoting serializes by type and WCF serializes by data contract. This means that an object can be serialized as one type at one end and deserialized as another type at the other end, as long as the two share the same contract. Among other things, this makes it possible to create different version of the same object which behave differently depending on where they are located (e.g. client-side or server-side). I am trying to implement a variation on this, but I'm running into trouble. I have the following object and service definition:



[DataContract]
public class MyData { ... }

[ServiceContract]
public interface IService {
[OperationContract]
void Process(MyData data);
}

In the service implementation application, I have the following definitions:



[DataContract(Name = "MyData")]
public class MyDerivedData : MyData { ... }

public class MyService : IService {
public void Process(MyData data) { }
}

When the data argument is deserialized on the server side, I want it to be deserialized as MyDerivedData instead of MyData. MyDerivedData does not add any contract data to MyData, only behaviors (i.e. methods) and server-specific properties which will be set after deserialization.

I have tried everything I could think of to make this work, including adding MyDerivedData as a known type to every place I could find (the operation using ServiceKnownTypeAttribute, the service using KnownTypeAttribute, and the MyData class using the configuration file). But no matter what I do, the data argument is always deserialized as a MyData instance.

Can anyone suggest how I might accomplish this Everything I have read says it should be possible, but I just can't figure it out...




Re: Windows Communication Foundation (Indigo) Deserializing data as a derived type

Brian McNamara - MSFT

Known types are the right way to do this.

I think your "Name=..." on the derived attribute may be the problem. If your derived type has the same name as the base, I think the service will assume it is the base (it will use the Name to decide which concrete type to deserialize into, I think). Can you try changing/removing the Name property on the derived DataContract attribute, and using the known type attributes (on both server and client) and see how it turns out then






Re: Windows Communication Foundation (Indigo) Deserializing data as a derived type

CommonGenius.com

Actually I tried that first. Originally MyDerivedData was just called MyData (in a different .NET namespace than the MyData in the common library), with no explicit naming in the DataContractAttribute. I got the same result.




Re: Windows Communication Foundation (Indigo) Deserializing data as a derived type

Carlos Figueira - MSFT

This should work:

public class Post1662129

{

[DataContract]

public class MyData

{

[DataMember]

public int i = 123;

}

[DataContract(Name = "MyData")]

public class MyDerivedData : MyData

{

public override string ToString()

{

return String.Format("In MyDerivedData; i = {0}.", this.i);

}

}

[ServiceContract(Name="IMyContract")]

public interface IServerContract

{

[OperationContract]

void Process(MyDerivedData data);

}

[ServiceContract(Name = "IMyContract")]

public interface IClientContract

{

[OperationContract]

void Process(MyData data);

}

public class ServiceClass : IServerContract

{

public void Process(MyDerivedData data)

{

Console.WriteLine(data);

}

}

public static void Main()

{

string baseAddress = "http://localhost:8000/Service";

ServiceHost host = new ServiceHost(typeof(ServiceClass), new Uri(baseAddress));

host.AddServiceEndpoint(typeof(IServerContract), new BasicHttpBinding(), "");

host.Open();

ChannelFactory<IClientContract> factory = new ChannelFactory<IClientContract>(new BasicHttpBinding(), new EndpointAddress(baseAddress));

IClientContract proxy = factory.CreateChannel();

proxy.Process(new MyData());

((IClientChannel)proxy).Close();

factory.Close();

host.Close();

}

}

Basically, we have two contracts which are equivalent (based on the "Name" property of the [ServiceContract]), one for the client and one for the service. The server receives a MyDerivedData (which has the same DataContract as MyData, as you mentioned that you only added new behavior to this class, not data). For WCF, as long as the contracts (data and service) are equivalent, they can be used in the two parts of the communication.





Re: Windows Communication Foundation (Indigo) Deserializing data as a derived type

CommonGenius.com

I agree that should work. However, it would require me to perform double maintenance on my service contracts. In this small example that's not a big deal, but when we're talking about an enterprise application it becomes a very big deal.

Is there not a better way to handle this, one that would not require me to perform such double maintenance






Re: Windows Communication Foundation (Indigo) Deserializing data as a derived type

sholman

I would not use inheritance via MyData to control server side behavior. I would separate client and server behaviors with respect to the data contract then place those behaviors in separate classes with a constructor that uses MyData.

class MyDataBehavior

{

}

class MyDataServerBehavior: MyDataBehavior

{

MyDataServerBehavior(MyData value)

{.....}

}

class MyDataClient: MyDataBehavior

{

MyDataServerBehavior(MyData value)

{.....}

}





Re: Windows Communication Foundation (Indigo) Deserializing data as a derived type

CommonGenius.com

That would probably work as a workaround. However, it is not the optimal solution, since it requires one of the following:

1) Re-design the object model to separate the data from the behavior in general. So on my server, instead of writing code to access Person.FirstName, access Person.Data.FirstName instead. This is not good object-oriented design, and results in the implementation of the transport mechanism intruding on the design of the system itself, which I want to avoid.

2) Incorporate the data from PersonData into my server-side Person object by re-exposing its data through propeties. This makes the object model cleaner, but now I am back to doing double maintenance, since anything I add to my PersonData object also has to be added and re-exposed through Person. I understand that this kind of double maintenance is necessary when using type composition, but in this case the composition is being artificially forced due the transport mechanism, which, again, I would like to avoid.

All I want is to use normal object-oriented principles in the design of my system, and for WCF to not be an obstacle to that. It doesn't seem like that's too much to ask.






Re: Windows Communication Foundation (Indigo) Deserializing data as a derived type

sholman

You could also implement a copy constructor on MyDataDerived but this also requires work and you may not find it optimal.

MyDataDerived(MyData value)

{....}





Re: Windows Communication Foundation (Indigo) Deserializing data as a derived type

Brian McNamara - MSFT

I think I misunderstood the question the first time. I think I understand what you are after now. Let me say what I think you want:

You want the client and the server to share the same ServiceContract interface, that uses MyData as the method argument.

You want the client to send a concrete object whose type is MyData.

You want the server to deserialize this argument into a concrete object of type MyDerivedData.

Is that correct

If so, I would think using a behavior to replace the server formatter with one that uses a DataContractSurrogate might be a good answer. Check out this sample. http://msdn2.microsoft.com/en-us/library/ms751540.aspx While one typically uses a surrogate to deal with serializing/deserializing a type that is not marked up with DataContract, I imagine it will work in this scenario as well, though I have not tried it. (Note that the sample also does crazy stuff with an IWsdlExporter to deal with metadata, which you would not need.)

Anyway, can you try that out






Re: Windows Communication Foundation (Indigo) Deserializing data as a derived type

CommonGenius.com

You are correct, that is what I am looking for. IDataContractSurrogate might work. However, it would come back to using the equivalent of a copy constructor, which has the same disadvantages in every platform, most notably that it requires double maintenance (every time I add data to the class I have to remember to go to the copy constructor and handle copying that data). I would rather avoid this.

Is this really that unusual or difficult a request With all the talk of how WCF allows the abstraction of data contracts away from concrete types, I don't understand why there isn't a simple way, at the operation or the service level, to say "this contract (specified by name and namespace) should be deserialized as this concrete type", and as long as the contracts match it should work. I understand that the operation contract itself supplies that information initially, but in an internal environment where code libraries are shared, I don't want to have to re-implement my entire service contract just to get this one type to be deserialized as a derived type.

There seem to be a number of issues coming up lately where WCF does not seem to fit well in internal development environments. For all the work that was put into creating contracts for publically visible services, where the contract has to be created from scratch anyway, it seems that very little was done to make things easy for internal application developers, where contracts don't need to be discovered and code libraries are typically shared across client and server applications. Is this an area that was considered when the design goals of WCF were formulated






Re: Windows Communication Foundation (Indigo) Deserializing data as a derived type

TrevorW

>>With all the talk of how WCF allows the abstraction of data contracts away from concrete types..

Sorry, what talk That is simply not true (IMO). .Net 2.0 - the code, not the .NET 3.0 communication block makes that claim. WCF requires concrete types and has some "workarounds" for non-concrete types.

Umm, maybe some people may yell at me for this, but WCF is designed, supported, and managed to handle SOA application blocks. In SOA, the contract specifies everything: the contract, the callback(if any), the messages, the faults, etc. It is designed such that a third-party can obtain all it needs to communicate with the service host.

From what I gather, you don't want an SOA-based communication channel. I have been SCREAMING at the WCF team to get this. I will say it again: PLEASE, support communication where the client has EXPLICIT knowledge about the data/domain object. It is just plain dumb to redefine your data for serialization across the communication channel when your client has explicit knowledge.

For me, what I did: I dropped WCF-based serialization. I cannot force some data to meet newer Data Contract standards, defining known types is retarded in a scenario where the client has the domain library and you know it: I know - explicitly - that 100% of the time - my client already knows the type. I tried the NetDataContractAttribute and it simply has quirks that blow up. So, I have been in heavenly bliss ever since I pre-serialized the objects before sending them through a WCF contract.( I.e. I send a byte[] and the Type as an enumeration value as part of the contract). Now, one contract handles multiple object types and its wonderful - no more unexpected why did you fail now bs.

I cannot help myself, someone within the WCF team really needs to get that the massive fat surrounding SOA services IS necessary for a TRUE public service, but it is absolutely, disgustingly, ridiculously, horrible for communication channels that involve a client that has explicit knowledge about domain objects.

Sorry...just an opinion... I would suggest taking serialization into your own hands until the team gets it - it works wonderfully for me. If you want to have 5, 10, or 15 methods work in a contract (after spending months to get the first ones working by tweaking them), then you suddenly need a new method in a contract only to discover that WCF can't handle wht you need: you are simply "stuck" with - "Well, thats the way it works!" Or... you get things working great... until that day you change your domain library and the version changes, but the domain objects did not, and discover that WCF starts denying access because of a version change, but the data object did not change - just the version for the library...so.. If the object serializes/deserializes without missing properties and without failing, why would it simply crash from a version change Hmmm I don't know, but it does.

Anyway, I will try until my breath turns blue for the WCF team to understand, but I am better off breathing and dropping WCF from the serialization process until they do. All the other pieces are awesome (IMO) .. the serialization is the most obtrusive, concrete requiring, hunk-o-junk, I have ever worked with.

Again.. I expect lots of "you are full-O-"#%^$" answers, but that is my opinion.

Trevor





Re: Windows Communication Foundation (Indigo) Deserializing data as a derived type

Buddhike de Silva

IMO, the way WCF handles this is perfectly right. You cannot do this up-casting in typical OO programming either. For example, consider the following snippet:

class MyData

{

}

class MyDerivedData : MyData

{

}

class srv

{

static void Main(string[] args)

{

DoSomething(new MyData());

}

static void DoSomething(MyData b)

{

MyDerivedData d = (MyDerivedData)b;

}

}

Therefore we have to rely on something like a copy constructor if we are willing to construct an instance of derived class with the base class instance in our hand. Likewise when it comes to serialization/deserialization of data contracts, you have to count on one of methods suggested above to achieve your goal.

IMO, when you use typical data contract inheritance your operations can expect a Person. So the client can send any variation of Person, such as Manager, Engineer, Electrician etc, etc. Server is still able to identify it as a Person. But if the client sends a plain Person, the server would not be able to figure out which kind of a person it is without a bit of twiddling¡­

My two cents Wink

Cheers,

Buddhike






Re: Windows Communication Foundation (Indigo) Deserializing data as a derived type

TrevorW

>>Likewise when it comes to serialization/deserialization of data contracts, you have to count on one of methods suggested above to achieve your goal.

No, I don't - really - seriously - I do not. I only have to in I donlt serialize it.

How about this:

class MyData

{

}

class MyDerivedData : MyData

{

}

class srv

{

static void Main(string[] args)

{

MyDerivedData d = new MyDerivedData();

d.BlahBlah
byte[] b = Serializer.Serialize(d);

DoSomething(b, DomainType.MyDerivedType);

}

static void DoSomething(Byte[] b, DomainType domainType)

{

...yada ... yada

}

}





Re: Windows Communication Foundation (Indigo) Deserializing data as a derived type

Brian McNamara - MSFT

CommonGenius.com wrote:

However, it would come back to using the equivalent of a copy constructor, which has the same disadvantages in every platform...

Is this really that unusual or difficult a request

I think it is unusual, I don't know that I've ever seen someone want this before.

What is it for What does MyDerivedData do differently from MyData How is this useful to you Maybe backing up to look at the bigger picture will provide an alternate solution.

CommonGenius.com wrote:

There seem to be a number of issues coming up lately where WCF does not seem to fit well in internal development environments. For all the work that was put into creating contracts for publically visible services, where the contract has to be created from scratch anyway, it seems that very little was done to make things easy for internal application developers, where contracts don't need to be discovered and code libraries are typically shared across client and server applications. Is this an area that was considered when the design goals of WCF were formulated

I have heard this feedback repeatedly from a variety of sources. I don't think these scenarios were prioritized as highly as other scenarios. No real 'answer' here, but some empathy anyway.




Re: Windows Communication Foundation (Indigo) Deserializing data as a derived type

TrevorW

Uggg.. I hate looking back at my own own posts where I was up for 20 hours and brain dead - OH MY!

However, I will still chime in every time I can.

1. There is a very large market for internal application uses. Most developers I communicate with are in this scenario versus true service-oriented with 3rd party consumers.

2. I got started with WCF because I just wanted to play - I am still very much learning. However, I was overwhelmed with all the overhead typically involved, or.. that most examples and answers assume 3rd party consumers are involved and it just stands out as "odd" to redefine all these elements are already defined. I don't have to - I know that now - but, boy did I have to dig to figure how to use WCF the "simple way". When someone is looking for an improvement over remoting, it is hard to swallow at first. Once, I was in - I slowly expanded into other areas and kept exploring. Now, I definetly prefer WCF over remoting - for many reasons. I think others - if they are helped into the realm, would be too.

3. Imagine the benefits of reduced overhead and simplicity of design/use if we can make one significant assumption - the client and server have intimate knowledge of each other. Are there not significant advantages for specifically focusing on using WCF solely for the purpose of safe, secure, reliable message transfers That is very different than including the "other" main role of WCF: which is to define the data, the faults, etc, etc. for 3rd parties to consume the services.

Its certainly worth considering, and I think targeted effort would be rewarded with great increases in user-base as well as increased customer satisfaction.

Trevor