Categories
C# .NET Managed Extensibility Framework

Dynamic DataContractSerializer KnownTypes with MEF

Have you ever used the .NET DataContractSerializer? Do you need to serialize types defined at runtime? Well then keep reading. There might be a simple solution to your problem. There are several ways of providing type information to the serializer.

The first method is the type provided to the serializer’s constructor. A second method is through a configuration file. This is particularly useful in the context of using Windows Communication Foundation (WCF) services particularly with third-party components. A third method is providing type information through the serializer’s KnownTypes property. This example is a variation on the last approach. The standard way of providing some known type information looks like this.

var serializer = new DataContractSerializer(typeof(TypeOne), new List<Type>(new[] { typeof(TypeTwo), typeof(TypeThree) });)

This standard approach provides a collection of known types when constructing the serializer. This works in many cases but what if you don’t know the types at design time? How about if they are defined in an assembly that is not referenced? The configuration file approach could solve this problem. What if you are using the serializer outside of WCF? Fortunately there is a simple solution. The Managed Extensibility Framework (MEF) comes to the rescue.

MEF facilitates loose coupling and runtime discovery of components. It warrants a post of its own but here is a high-level overview. MEF utilizes a CompositionContainer to expose exported types. Types are imported either through a constructor decorated with an [ImportingConstructor] attribute or members decorated with an [Import] attribute.

First I create an interface with a single collection property to store one or more types.

public interface IPersistable { IEnumerable<Type> Types { get; } }

Next I implemented the interface in the class I wanted to serialize.

[Export(typeof(IPersistable))] [DataContract] public class Order : IPersistable { [DataMember] public int Id { get; set; } [DataMember] public string ItemName { get; set; } [DataMember] public decimal Price { get; set; } public IEnumerable<Type> Types { get { return new[] { typeof(Order) }; } } public override string ToString() { return string.Format("Order - ID:{0} Item:{1} Price:${2}", Id, ItemName, Price); } }

Alternately a class that implements the interface and provides a collection of multiple types can be used. Either approach works fine. The last step is for the class that uses the serializer to import the type collections by using the [ImportMany] attribute.

public class DataPersistence { private readonly DataContractSerializer _serializer; [ImportingConstructor] public DataPersistence([ImportMany] IEnumerable<IPersistable> knownTypes) { if (knownTypes == null) throw new ArgumentNullException("knownTypes"); var types = knownTypes.SelectMany(t => t.Types); _serializer = new DataContractSerializer(typeof(object), types); } }

This is a simple way to dynamically provide type information to the DataContractSerializer. You can download the complete sample here.