问题
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