src/DurableTask.AzureStorage/DataContractJsonConverter.cs (84 lines of code) (raw):

// ---------------------------------------------------------------------------------- // Copyright Microsoft Corporation // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ---------------------------------------------------------------------------------- using System; using System.IO; using System.Reflection; using System.Runtime.Serialization; using System.Runtime.Serialization.Json; using Newtonsoft.Json; namespace DurableTask.AzureStorage { /// <summary> /// This class bridges <see cref="DataContractJsonSerializer"/> with Newtonsoft.Json. This serializer /// is slower, but it handles writing to <see cref="IExtensibleDataObject"/>, which Newtonsoft does not. /// A drawback of <see cref="DataContractJsonSerializer"/> is that ExtensionData Namespaces are not populated, /// meaning reading via the regular <see cref="DataContractSerializer"/> will not correctly hydrate extra fields /// from ExtensionData. However, it can still be done by using <see cref="DataContractJsonSerializer"/> instead. /// </summary> internal class DataContractJsonConverter : JsonConverter { public override bool CanConvert(Type objectType) { if (objectType == null) { throw new ArgumentNullException(nameof(objectType)); } return objectType.GetCustomAttribute<DataContractAttribute>() != null && typeof(IExtensibleDataObject).IsAssignableFrom(objectType); } /// <inheritdoc /> public override object ReadJson( JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { if (reader == null) { throw new ArgumentNullException(nameof(reader)); } if (objectType == null) { throw new ArgumentNullException(nameof(objectType)); } if (serializer == null) { throw new ArgumentNullException(nameof(serializer)); } using (var stream = new MemoryStream()) using (var writer = new StreamWriter(stream)) using (var jsonWriter = new JsonTextWriter(writer)) { jsonWriter.WriteToken(reader, writeChildren: true); jsonWriter.Flush(); stream.Position = 0; var contractSerializer = CreateSerializer(objectType, serializer); return contractSerializer.ReadObject(stream); } } /// <inheritdoc /> public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { if (writer == null) { throw new ArgumentNullException(nameof(writer)); } if (value == null) { writer.WriteNull(); return; } if (serializer == null) { throw new ArgumentNullException(nameof(serializer)); } using (var memoryStream = new MemoryStream()) { var contractSerializer = CreateSerializer(value.GetType(), serializer); contractSerializer.WriteObject(memoryStream, value); memoryStream.Position = 0; using (var streamReader = new StreamReader(memoryStream)) using (var jsonReader = new JsonTextReader(streamReader)) { writer.WriteToken(jsonReader, writeChildren: true); } } } private static DataContractJsonSerializer CreateSerializer(Type type, JsonSerializer serializer) { return new DataContractJsonSerializer( type, new DataContractJsonSerializerSettings { DateTimeFormat = new DateTimeFormat(serializer.DateFormatString), }); } } }