Сериализация Exception, сериализация newtonsoft заданий с DataContractSerializer
Обновление - проблема, с которой я столкнулся, была ошибка пользователя. Смотрите мой ответ ниже.
У меня есть класс, который я хочу добавить в DataContract WCF API, который должен быть "независимым от привязки"; т.е. он должен поддерживать несколько привязок, включая BasicHttp и NamedPipe. Класс, который я хочу добавить в контракт данных, использует Newtonsoft.Json.Linq.JObject для хранения данных члена:
[DataContract]
public class MyFacet
{
public MyFacet(string facetName)
{
Initialize();
FacetName = facetName;
}
internal JObject JsonObject { get; private set; }
[OnDeserializing] // required for deserialization to init JsonObject
private void OnDeserializing(StreamingContext c)
{
Initialize();
}
private void Initialize()
{
JsonObject = new JObject();
}
[DataMember]
public string FacetName
{
get
{
return GetProperty<string>("facet");
}
private set
{
SetProperty("facet", value);
}
}
public string ToJson()
{
return JsonObject.ToString(Newtonsoft.Json.Formatting.None);
}
public T GetProperty<T>(string key)
{
JToken value;
if (JsonObject.TryGetValue(key, out value))
{
return value.Value<T>();
}
return default(T);
}
public void SetProperty(string name, object value)
{
SetProperty(name, new JValue(value));
}
internal void SetProperty(string name, JToken value)
{
JsonObject[name] = value;
}
}
По разным причинам я хотел бы сохранить этот класс как есть, если это вообще возможно. Когда я пытаюсь сериализовать этот класс с помощью DataContractSerializer (в тестовом приложении), я получаю следующую ошибку:
System.Runtime.Serialization.SerializationException:
Type 'ConsoleTest.MyFacet' with data contract name
'MyFacet:http://schemas.datacontract.org/2004/07/ConsoleTest' is not expected.
Consider using a DataContractResolver or add any types not known statically to
the list of known types - for example, by using the KnownTypeAttribute attribute
or by adding them to the list of known types passed to DataContractSerializer.
Что, по сути, имеет смысл для меня. Но добавление различных типов Newtonsoft в качестве KnownTypes не работает - это приводит к ошибке "контракт рекурсивного сбора данных". Я думаю, у меня возникла бы та же проблема, если бы я попытался реализовать DataContractResolver.
Я считаю, что могу сериализовать JObject в XML с помощью сериализатора Newtonsoft. Кажется, у меня есть несколько вариантов:
- Используйте IDataContractSurrogate и предоставьте десериализованный суррогат объекта JObject.
- Используйте IClientMessageFormatter для создания пользовательских сериализации / десериализации
- Как-то еще сконфигурируйте / переопределите "систему" де / сериализации для использования сериализатора Newtonsoft вместо или вместе с DataContractSerializer.
И я беспокоюсь о необходимости поддерживать различные привязки. Именованный канал использовал двоичное кодирование, и я не уверен, как это повлияет на эту проблему сериализации - возможно, это означает, что я должен использовать суррогат?
2 ответа
Оказывается, это была ошибка пользователя 100%. В моем тестовом модуле сериализации я передавал неверный тип при создании DataContractSerializer. Следующее демонстрирует ОШИБКУ:
Console.WriteLine("serializing...");
MyFacet facet = new MyFacet("MyFacet");
// On the following line, I was passing the wrong type to the ctor.
// Needed to pass "MyFacet" here, not "Person"
//!ERROR
DataContractSerializer serializer = new DataContractSerializer(typeof(Person));//!ERROR
var settings = new XmlWriterSettings { Indent = true };
using (var writer = XmlWriter.Create(fileName, settings))
serializer.WriteObject(writer, facet);
Как только я исправил ошибку, класс в оригинальном посте сериализовался просто отлично. Сообщение об ошибке, которое я первоначально получал, действительно сбило меня с толку. Я предполагал, что что-то было в JObject или одном из типов Newtonsoft, вызывающих проблему, хотя на самом деле я даже не пытался сериализовать ни один из этих типов.
Я думаю, KnownType
не поможет - так как он должен помочь только "найти" тип, когда wcf DataContractSerializer
должен знать, как сериализовать.
И это не так, потому что JObject
не включает в себя DataContract
а также DataMember
атрибутов.
Если JObject
является сериализуемым XML, я бы решил использовать сериализацию XML вместо сериализации DataContract.