DataContractJsonSerializer with object type member

陌路散爱 提交于 2020-01-25 07:09:22

问题


I have the following serialization method:

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);
}

I'm trying to serialize the following object:

[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; }
}

I'm facing a serialization exception related to the object parameter containing an AuthorizationRequest object having DataContract and DataMember too. Here is the complete exception stack trace :

L'exception System.Runtime.Serialization.SerializationException n'a pas été gérée par le code utilisateur HResult=-2146233076
Message=Le type 'AF.WS.ProjetEtDevis.DAP.MNG.BusinessEntities.AuthorizationRequest' avec le nom de contrat de données 'AuthorizationRequest:http://schemas.datacontract.org/2004/07/AF.WS.ProjetEtDevis.DAP.MNG.BusinessEntities' n'est pas attendu. Utilisez un DataContractResolver si vous utilisez DataContractSerializer ou ajoutez tous les types non connus statiquement à la liste des types connus, par exemple en utilisant l'attribut KnownTypeAttribute ou en les ajoutant à la liste des types connus qui est transmise au sérialiseur.
Source=System.Runtime.Serialization StackTrace: à System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeAndVerifyType(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, Boolean verifyKnownType, RuntimeTypeHandle declaredTypeHandle, Type declaredType) à System.Runtime.Serialization.Json.XmlObjectSerializerWriteContextComplexJson.SerializeWithXsiType(XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle objectTypeHandle, Type objectType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle, Type declaredType) à System.Runtime.Serialization.XmlObjectSerializerWriteContext.InternalSerialize(XmlWriterDelegator xmlWriter, Object obj, Boolean isDeclaredType, Boolean writeXsiType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle) à System.Runtime.Serialization.XmlObjectSerializerWriteContextComplex.InternalSerialize(XmlWriterDelegator xmlWriter, Object obj, Boolean isDeclaredType, Boolean writeXsiType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle) à WriteMessageToJson(XmlWriterDelegator , Object , XmlObjectSerializerWriteContextComplexJson , ClassDataContract , XmlDictionaryString[] ) à System.Runtime.Serialization.Json.JsonClassDataContract.WriteJsonValueCore(XmlWriterDelegator jsonWriter, Object obj, XmlObjectSerializerWriteContextComplexJson context, RuntimeTypeHandle declaredTypeHandle) à System.Runtime.Serialization.Json.XmlObjectSerializerWriteContextComplexJson.WriteDataContractValue(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle) à System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeWithoutXsiType(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle) à System.Runtime.Serialization.Json.DataContractJsonSerializer.InternalWriteObjectContent(XmlWriterDelegator writer, Object graph) à System.Runtime.Serialization.Json.DataContractJsonSerializer.InternalWriteObject(XmlWriterDelegator writer, Object graph) à System.Runtime.Serialization.XmlObjectSerializer.InternalWriteObject(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver) à System.Runtime.Serialization.XmlObjectSerializer.WriteObjectHandleExceptions(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver) à System.Runtime.Serialization.Json.DataContractJsonSerializer.WriteObject(XmlDictionaryWriter writer, Object graph) à System.Runtime.Serialization.Json.DataContractJsonSerializer.WriteObject(Stream stream, Object graph) à AF.WS.ProjetEtDevis.DAP.MNG.BusinessLogic.AuthorizationRequestMngService.Serialize(Message message) dans C:\src\Git\AF.WS.ProjetEtDevis.DAP.MNG\Sources\AF.WS.ProjetEtDevis.DAP.MNG.BusinessLogic\AuthorizationRequestMngService.cs:ligne 134 à AF.WS.ProjetEtDevis.DAP.MNG.BusinessLogic.AuthorizationRequestMngService.GenerateEdaMessage(String topicName, AuthorizationRequest request) dans C:\src\Git\AF.WS.ProjetEtDevis.DAP.MNG\Sources\AF.WS.ProjetEtDevis.DAP.MNG.BusinessLogic\AuthorizationRequestMngService.cs:ligne 124 à AF.WS.ProjetEtDevis.DAP.MNG.UnitTests._2._BusinessLogic_Tests.AuthorizationRequestMngServiceUnitTest.ShouldSerializeAuthorizationRequest_WhenCorrectDataSent() dans C:\src\Git\AF.WS.ProjetEtDevis.DAP.MNG\Sources\AF.WS.ProjetEtDevis.DAP.MNG.UnitTests\2. BusinessLogic Tests\AuthorizationRequestMngServiceUnitTest.cs:ligne 251 InnerException:

In English the message is:

Type 'AF.WS.ProjetEtDevis.DAP.MNG.BusinessEntities.AuthorizationRequest' with data contract name 'AuthorizationRequest:http://schemas.datacontract.org/2004/07/AF.WS.ProjetEtDevis.DAP.MNG.BusinessEntities' is not expected. 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.

Please note that I can't use other serializer than DataContractJsonSerializer


回答1:


You need to inform DataContractJsonSerializer upfront of the possible types that might occur in the object Payload member by using the known type mechanism. From the docs:

Polymorphism

Polymorphic serialization consists of the ability to serialize a derived type where its base type is expected. This is supported for JSON serialization by WCF comparable to the way XML serialization is supported. For example, you can serialize MyDerivedType where MyBaseType is expected, or serialize Int where Object is expected...

Preserving Type Information

As stated earlier, polymorphism is supported in JSON with some limitations...

To preserve type identity, when serializing complex types to JSON a "type hint" can be added, and the deserializer recognizes the hint and acts appropriately. The "type hint" is a JSON key/value pair with the key name of "__type" (two underscores followed by the word "type"). The value is a JSON string of the form "DataContractName:DataContractNamespace" (anything up to the first colon is the name).

The most common way to do this is to apply KnownTypeAttribute to the relevant data contract object itself:

[DataContract]
[KnownType(typeof(AuthorizationRequest))]
public class Message
{
    [DataMember(Name = "technical", Order = 1)]
    public Technical Technical;

    [DataMember(Name = "payload", Order = 2)]
    public object Payload;
}

You can also use the DataContractJsonSerializer(Type, IEnumerable<Type>) constructor:

var ser = new DataContractJsonSerializer(typeof(Message), new [] { typeof(AuthorizationRequest)});

Having done so, your serialized JSON will look as follows, with the polymorphic type hint __type included to specify the payload type:

{
  "technical": {
    "topic": "my topic",
    "nature": "my nature",
    "event_id": "1010101"
  },
  "payload": {
    "__type": "AuthorizationRequest:#Question48583688"
  }
}

If you need more flexibility in how known types are specified, see Configuring Known Types Dynamically – Introducing the DataContractResolver. But be sure not to allow any and all types to be resolved. If you do, you will introduce security problems into your app like those discussed in TypeNameHandling caution in Newtonsoft Json.



来源:https://stackoverflow.com/questions/48583688/datacontractjsonserializer-with-object-type-member

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!