編輯
我們現在有一個開源項目,以幫助遷移。
https://github.com/Weingartner/Migrations.Json.Net
原來的答案
這裏是JsonConverter我寫的解決我問題。我所做的是使用Guid屬性(通常用於com互操作)來標記我的序列化。然後我提供了一個基於guid的工廠。該工廠基於ninject DI框架。
代碼的臨界線是在ReadJson方法
var document = _Kernel.Get<IWeinCadDocument>(typeId.ToString());
這裏創建我的基礎上,GUID字符串的正確類型的文檔的一個實例。這些類型使用以下功能預先註冊。
public void BindDocumentTypes(params Type[] types)
{
Debug.Assert
(types.All(p => typeof (IWeinCadDocument).IsAssignableFrom(p)));
foreach (var documentType in types)
{
Kernel.Bind<IWeinCadDocument>()
.To(documentType)
.Named(documentType.GUID.ToString());
}
}
其可以以下面的方式被用來註冊的一組類型及其GUID。
BindDocumentTypes(
typeof (ADocument), typeof (BDocument), typeof (CDocument)
);
爲了確保GUID不軟件的版本之間改變,甚至編譯我們執行的GUID像這樣與屬性。
[Guid("4882176A-751A-4153-928A-915BEA87FAB3")]
public class ADocument : WeinCadDocumentBase<ADocument>
{
public ADocument(IWeinCadDocumentStorage storage)
: base(storage)
{
}
public override object PersistentData
{
get
{
return new DocumentData(10, 20);
}
}
}
完整的JSonConverter如下。
public class WeinCadDocumentConverter : JsonConverter
{
private readonly IKernel _Kernel;
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var document = value as IWeinCadDocument;
Debug.Assert(document != null, "document != null");
AssertThatWeHaveACustomGuidSet(value);
writer.WriteStartObject();
writer.WritePropertyName("InstanceId");
writer.WriteValue(document.InstanceId);
writer.WritePropertyName("TypeId");
writer.WriteValue(document.GetType().GUID);
writer.WritePropertyName("Name");
writer.WriteValue(document.Name);
writer.WritePropertyName("Data");
serializer.Serialize(writer, document.PersistentData);
writer.WriteEndObject();
}
/// <summary>
/// The object need a custom GuidAttribute to be set on the class otherwise the
/// GUID may change between versions of the code or even runs of the applications.
/// This Guid is used for identifying types from the document store and calling
/// the correct factory.
/// </summary>
/// <param name="value"></param>
private static void AssertThatWeHaveACustomGuidSet(object value)
{
var attr = System.Attribute.GetCustomAttributes(value.GetType())
.Where(a => a is GuidAttribute)
.ToList();
if (attr.Count == 0)
throw new ArgumentException
(String.Format
(@"Type '{0}' does not have a custom GuidAttribute set. Refusing to serialize.",
value.GetType().Name),
"value");
}
public override object ReadJson
(JsonReader reader,
Type objectType,
object existingValue,
JsonSerializer serializer)
{
JObject json = JObject.Load(reader);
var props = json.Properties().ToList();
var instanceId = (Guid) props[0].Value;
var typeId = (Guid) props[1].Value;
var name = (string) props[2].Value;
var data = props[3].Value;
var document = _Kernel.Get<IWeinCadDocument>(typeId.ToString());
document.PersistentData = data;
document.InstanceId = instanceId;
document.Name = name;
return document;
}
public override bool CanConvert(Type objectType)
{
return typeof (IWeinCadDocument).IsAssignableFrom(objectType);
}
public WeinCadDocumentConverter(IKernel kernel)
{
_Kernel = kernel;
}
}