Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using custom DataContractResolver in WCF, to transport inheritance trees involving generics

I've got a WCF service, in which there are operations which accept a non-generic base class as parameter.

[DataContract]
class Foo
{ ... }

This base class is in turn inherited, by such generics classes as

[DataContract]
class Bar<T> : Foo
{ ... }

To get this to work, I'd previously have to register KnownTypes for the Foo class, and have these include all possible variations of Bar (such as Bar<string>, Bar<int> and even Bar<List<string>>).

With the DataContractResolver in .NET 4, however, I should be able to build a resolver which properly stores (and restores) the classes.

My questions:

  1. Are DataContractResolvers typically only used on the service side, and not by the client? If so, how would that be useful in this scenario?

  2. Am I wrong to write a DataContractResolver which serializes the fully qualified type name of a generic type, such as Bar`1[List`1[string, mscorlib], mscorlib] ? Couldn't the same DataContractResolver on the client side restore these types?

like image 534
Benson Avatar asked Mar 13 '10 11:03

Benson


2 Answers

I have used a DataContractResolver before; and these are my findings:

  1. Both client AND server require the resolver; as serialization and deserialization takes place at both ends. Obviously, the same Resolver is used.
  2. The type names are a standard part of the information the DataContractSerializer produces. However, it is just the type NAME, not a fully (assembly) qualified name

Basically, a custom resolver allows you to add it to your WCF client and server as Behavior:

`foreach (OperationDescription operation in myWCFService.Description.Endpoints[0].Contract.Operations)
    {
      operation.Behaviors.Find<DataContractSerializerOperationBehavior>()
          .DataContractResolver = new MyDataContractResolver();
    }`

For the client, you do the same:

      `foreach (var operation in base.ChannelFactory.Endpoint.Contract.Operations)
  {
    operation.Behaviors.Find<DataContractSerializerOperationBehavior>()
        .DataContractResolver = new MyDataContractResolver();
  }`

My resolver dynamically loads types from a configured location and based on some attribute, caches them. I can provide you some sample code if you like - it's all pretty basic.

KnownTypeAttribute (e.g. using a provided method to return all known types) is also usable; but the custom resolver allows a more flexible approach, such as dynamically loading types (e.g. a plugin system) and doing your own mapping (Type => type name and vice versa)

like image 81
NoDaldPrutm Avatar answered Nov 04 '22 05:11

NoDaldPrutm


I would expect that to work at both ends, but I'm not sure it is a great idea; it requires extra configuration, and won't work on Silverlight etc. But it'll probably work for "full" .NET with the same bits at each end.

like image 1
Marc Gravell Avatar answered Nov 04 '22 03:11

Marc Gravell