DataContractJsonSerializer с членом типа объекта
У меня есть следующий метод сериализации:
private string Serialize(Message message)
{
byte[] json;
using (var ms = new MemoryStream())
{
var ser = new DataContractJsonSerializer(typeof(Message));
ser.WriteObject(ms, message);
json = ms.ToArray();
}
return Encoding.UTF8.GetString(json, 0, json.Length);
}
Я пытаюсь сериализовать следующий объект:
[DataContract]
public class Message
{
[DataMember(Name = "technical", Order = 1)]
public Technical Technical;
[DataMember(Name = "payload", Order = 2)]
public object Payload;
}
[DataContract]
public class Technical
{
[DataMember(Name = "topic", Order = 1)]
public string Topic { get; set; }
[DataMember(Name = "nature", Order = 2)]
public string Nature { get; set; }
[DataMember(Name = "event_id", Order = 3)]
public string EventId { get; set; }
}
Я столкнулся с исключением сериализации, связанной с object
параметр, содержащий AuthorizationRequest
объект, имеющий DataContract
а также DataMember
тоже. Вот полная трассировка стека исключений:
L'exception System.Runtime.Serialization.SerializationException без дополнительной информации об использовании кода HResult=-2146233076
Сообщение = тип файла "AF.WS.ProjetEtDevis.DAP.MNG.BusinessEntities.AuthorizationRequest" запрос подтверждения доступа "AuthorizationRequest: http://schemas.datacontract.org/2004/07/AF.WS.ProjetEtDevis.DAP.MNG.BusinessEntities'n'est pas Participu. Использование данных DataContractResolver с использованием данных DataContractSerializer с различными типами данных, не зависящими от типа connus, в частности, с точки зрения использования Известные типы атрибутов, которые вы можете использовать в качестве альтернативы, могут быть изменены.
Источник =System.Runtime.Serialization StackTrace: à System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeAndVerifyType(DataContract DataContract, XmlWriterDelegator XMLWriter, OBJ Object, Boolean verifyKnownType, RuntimeTypeHandle declaredTypeHandle, Тип declaredType) à System.Runtime.Serialization.Json.XmlObjectSerializerWriteContextComplexJson.SerializeWithXsiType(XmlWriterDelegator XMLWriter, OBJ Объект, RuntimeTypeHandle objectTypeHandle, Тип ObjectType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle, Тип declaredType) меню System.Runtime.Serialization.XmlObjectSerializerWriteContext.InternalSerialize(XmlWriterDelegator XMLWriter, OBJ Object, Boolean, Boolean isDeclaredType writeXsiType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle) à System.Runtime.Serialization.XmlObjectSerializerWriteContextComplex.InternalSerialize(XmlWriterDelegator xmlWriter, Object obj, логический isDeclaredType, логический writeXsiType, объявленный Int32TypeID, RuntimeTyp eHandle declaredTypeHandle) меню WriteMessageToJson(XmlWriterDelegator, объект, XmlObjectSerializerWriteContextComplexJson, ClassDataContract, XmlDictionaryString[]) меню System.Runtime.Serialization.Json.JsonClassDataContract.WriteJsonValueCore(XmlWriterDelegator jsonWriter, OBJ Object, XmlObjectSerializerWriteContextComplexJson контексте, RuntimeTypeHandle declaredTypeHandle) а System.Runtime.Serialization.Json.XmlObjectSerializerWriteContextComplexJson.WriteDataContractValue(DataContract DataContract, XmlWriterDelegator XMLWriter, OBJ Объект, RuntimeTypeHandle declaredTypeHandle) меню System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeWithoutXsiType(DataContract DataContract, XmlWriterDelegator XMLWriter, OBJ Объект, RuntimeTypeHandle declaredTypeHandle) а System.Runtime.Serialization.Json.DataContractJsonSerializer.InternalWriteObjectContent(модуль записи XmlWriterDelegator, граф объектов) à System.Runtime.Serialization.Json.DataContractJsonSerializer.InternalWriteObject(Писатель XmlWriterDelegator, граф объектов) Runtime.Serialization.Json.DataContractJsonSerializer.WriteObject(модуль записи XmlDictionaryWriter, граф объектов). Сериализация (сообщение сообщения) dans C:\src\Git\AF.WS.ProjetEtDevis.DAP.MNG\Sources\AF.WS.ProjetEtDevis.DAP.MNG.BusinessLogic\AuthorizationRequestMngService.cs:ligne 134 à AF.WS.ProjetED.DAP.MNG.BusinessLogic.AuthorizationRequestMngService.GenerateEdaMessage(String topicName, запрос AuthorizationRequest) dans C:\src\Git\AF.WS.ProjetEtDevis.DAP.MNG\Sources\AF.WS.: \ SRC \Git\AF.WS.ProjetEtDevis.DAP.MNG\Sources\AF.WS.ProjetEtDevis.DAP.MNG.UnitTests\2. BusinessLogic Tests\AuthorizationRequestMngServiceUnitTest.cs:ligne 251 InnerException:
На английском это сообщение:
Введите "AF.WS.ProjetEtDevis.DAP.MNG.BusinessEntities.AuthorizationRequest" с именем контракта данных "AuthorizationRequest: http://schemas.datacontract.org/2004/07/AF.WS.ProjetEtDevis.DAP.MNG.BusinessEntities" неожиданно. Добавьте любые типы, которые не известны статически, в список известных типов - например, с помощью атрибута KnownTypeAttribute или добавив их в список известных типов, переданных DataContractSerializer.
Обратите внимание, что я не могу использовать другой сериализатор, кроме DataContractJsonSerializer
1 ответ
Вам необходимо сообщить DataContractJsonSerializer
заранее возможных типов, которые могут возникнуть в object Payload
член с помощью механизма известного типа. Из документов:
Полиморфизм
Полиморфная сериализация состоит из возможности сериализации производного типа там, где ожидается его базовый тип. Это поддерживается для сериализации JSON WCF, сравнимой с тем, как поддерживается сериализация XML. Например, вы можете сериализовать MyDerivedType, где ожидается MyBaseType, или сериализовать Int, где ожидается Object...
Сохранение информации о типе
Как говорилось ранее, полиморфизм поддерживается в JSON с некоторыми ограничениями...
Чтобы сохранить идентичность типов, при сериализации сложных типов в JSON можно добавить "подсказку типа", а десериализатор распознает подсказку и будет действовать соответствующим образом. "Подсказка типа" - это пара ключ / значение JSON с именем ключа "__type" (два подчеркивания, за которыми следует слово "type"). Значение представляет собой строку JSON в форме "DataContractName:DataContractNamespace" (имя до любого двоеточия является первым).
Самый распространенный способ сделать это - применить KnownTypeAttribute
к самому объекту данных данных договора:
[DataContract]
[KnownType(typeof(AuthorizationRequest))]
public class Message
{
[DataMember(Name = "technical", Order = 1)]
public Technical Technical;
[DataMember(Name = "payload", Order = 2)]
public object Payload;
}
Вы также можете использовать DataContractJsonSerializer(Type, IEnumerable<Type>)
конструктор:
var ser = new DataContractJsonSerializer(typeof(Message), new [] { typeof(AuthorizationRequest)});
Сделав это, ваш сериализованный JSON будет выглядеть следующим образом с подсказкой полиморфного типа __type
включено для указания типа полезной нагрузки:
{
"technical": {
"topic": "my topic",
"nature": "my nature",
"event_id": "1010101"
},
"payload": {
"__type": "AuthorizationRequest:#Question48583688"
}
}
Если вам нужно больше гибкости в том, как указываются известные типы, см. Динамическая настройка известных типов - Представление DataContractResolver. Но будьте уверены, чтобы не разрешить все типы. Если вы это сделаете, вы добавите в свое приложение проблемы безопасности, подобные тем, которые обсуждались в разделе "Предупреждение TypeNameHandling в Newtonsoft Json".