I have following setup in a MEF application:
Assembly MyBaseAssembly:
namespace My.Namespace
{
[DataContract]
public class Container
{
[DataMember]
public Data Item { get; set; }
}
[DataContract]
public class Data
{
[DataMember]
public string Foo { get; set; }
}
}
Assembly SecondAssembly, references the MyBaseAssembly:
namespace My.Another.Namespace
{
[DataContract]
public class SecondData : Data
{
[DataMember]
public string Bar { get; set; }
}
}
Somewhere deep inside of my application I create a Container
object:
Container container = new Container();
container.Item = new SecondData { Bar = "test" };
I want to serialize and de-serialize the container
object. Since the SecondAssembly is a MEF-module, I need to dynamically detect and resolve the types in the data contract, so the KnownTypeAttribute
is not a good solution.
I created a custom DataContractResolver
, but I don't know how do I get the assembly information for de-serialization.
On serialization, I get following XML:
<d4p1:SecondData
xmlns:d6p1="http://schemas.datacontract.org/2004/07/My.Another.Namespace"
i:type="d7p1:My.Another.Namespace.SecondData">
...
</d4p1:SecondData>
This is the default DataContract
serialization behavior: we get the type name and the type namespace, but there is no (explicit) assembly information!
Trying to de-serialize this XML, I cannot determine which assembly to use for resolving the type:
class SerializationTypeResolver : DataContractResolver
{
...
public override Type ResolveName(string typeName, string typeNamespace, Type declaredType, DataContractResolver knownTypeResolver)
{
Type result = knownTypeResolver.ResolveName(typeName, typeNamespace, declaredType, null);
if (result == null)
{
// Here, I cannot rely on the declaredType parameter,
// because it contains the declared type which is Data from MyBaseAssembly.
// But I need the SecondData from the SecondAssembly!
string assemblyName = ???; // How do I get this assembly name?
string fullTypeName = typeName + ", " + assemblyName;
result = Type.GetType(fullTypeName);
}
return result;
}
}
So my question is: what is the good way to store and get assembly name while serializing and de-serializing the DataContract
s?
Why not use AssemblyQualifiedName already when serializing? Like this:
internal class SerializationTypeResolver : DataContractResolver {
public override bool TryResolveType(Type type, Type declaredType, DataContractResolver knownTypeResolver, out XmlDictionaryString typeName, out XmlDictionaryString typeNamespace) {
// not necessary to hardcode some type name of course, you can use some broader condition
// like if type belongs to another assembly
if (type.Name == "SecondData") {
XmlDictionary dictionary = new XmlDictionary();
// use assembly qualified name
typeName = dictionary.Add(type.AssemblyQualifiedName);
typeNamespace = dictionary.Add("http://tempuri.org"); // some namespace, does not really matter in this case
return true;
}
return knownTypeResolver.TryResolveType(type, declaredType, null, out typeName, out typeNamespace);
}
public override Type ResolveName(string typeName, string typeNamespace, Type declaredType, DataContractResolver knownTypeResolver) {
if (typeNamespace == "http://tempuri.org") {
return Type.GetType(typeName); // assembly qualified already
}
return knownTypeResolver.ResolveName(typeName, typeNamespace, declaredType, null);
}
}