Мы нашли, почему это не работает. Сразу после сериализации объекта мы идентифицируем полученную строку для большей читаемости. Затем мы записываем строку в файл:
public void SaveContractToJSON<T>(T contract, string filePath)
{
using (MemoryStream stream = new MemoryStream())
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));
serializer.WriteObject(stream, contract);
string json = Encoding.UTF8.GetString(stream.ToArray());
File.WriteAllText(filePath, json.IndentJSON());
}
}
Идентификация - фактически причина, почему десериализация не работала. Кажется, анализатор DataContractJsonSerializer действительно требователен. Если некоторые символы находятся между символом {и полем "__type", сериализатор теряется.
Например, эта строка будет правильно сериализована:
"{\"Elements\":[{\"__type\":\"ElementA:#Data\",\"Id\":1}]}"
Но эта следующая строка не будет сериализована.
"{\"Elements\":[ {\"__type\":\"ElementA:#Data\",\"Id\":1}]}"
Единственное отличие - это пробелы перед символом __type. Сериализация вызовет исключение MemberAccessException. Это вводит в заблуждение, потому что это поведение появляется только при десериализации в абстрактный список. Сериализация в абстрактное поле прекрасно работает независимо от символов.
Чтобы устранить эту проблему, не удаляя читабельность файла, строку можно изменить перед десерализацией. Например:
public T LoadContractFromJSON<T>(string filePath)
{
try
{
string text = File.ReadAllText(filePath);
text = Regex.Replace(text, "\\{[\\n\\r ]*\"__type", "{\"__type");
using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(text)))
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));
T contract = (T)serializer.ReadObject(stream);
return contract;
}
}
catch (System.Exception ex)
{
logger.Error("Cannot deserialize json " + filePath, ex);
throw;
}
}