using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization.Formatters;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
public string NotADate { get; set; }
public DateTime ADate { get; set; }
public DateTime AnotherDate { get; set; }
public int Id { get; set; }
public DateTime? DateTime { get; set; }
public Example Example { get; set; }
public static void Test()
static void TestExample()
var example = new Example
ADate = DateTime.Parse("2017-04-23T18:25:43.511Z", CultureInfo.InvariantCulture),
AnotherDate = DateTime.Parse("2017-04-23T18:25:43.511Z", CultureInfo.InvariantCulture),
var settings = new JsonSerializerSettings
ContractResolver = new ConfigurableContractResolver
}.Configure((s, e) => { e.Contract.AddDateProperties(); }),
var json = JsonConvert.SerializeObject(example, Formatting.Indented, settings);
Console.WriteLine(string.Format("Serialized {0}:", example));
static void TestAndValidate()
var settings = new JsonSerializerSettings
ContractResolver = new ConfigurableContractResolver
}.Configure((s, e) => { e.Contract.AddDateProperties(); }),
TypeNameHandling = TypeNameHandling.All,
TypeNameAssemblyFormat = FormatterAssemblyStyle.Full,
var root = new RootObject
DateTime = DateTime.Parse("2016-08-02 05:49:11.000Z", CultureInfo.InvariantCulture),
ADate = DateTime.Parse("2017-04-23T18:25:43.511Z", CultureInfo.InvariantCulture),
AnotherDate = DateTime.Parse("2017-04-23T18:25:43.511Z", CultureInfo.InvariantCulture),
var json = JsonConvert.SerializeObject(root, Formatting.Indented, settings);
Console.WriteLine(string.Format("Serialized {0}", root));
var root2 = JsonConvert.DeserializeObject<RootObject>(json, settings);
var json2 = JsonConvert.SerializeObject(root2, Formatting.Indented, settings);
Assert.IsTrue(json == json2);
Assert.IsTrue(JToken.DeepEquals(JToken.Parse(json).SelectToken("_date_properties_"), JToken.Parse(@"[""DateTime""]")));
Assert.IsTrue(JToken.DeepEquals(JToken.Parse(json).SelectToken("Example._date_properties_"), JToken.Parse(@"[""ADate"", ""AnotherDate""]")));
((ConfigurableContractResolver)settings.ContractResolver).ContractCreated += (o, e) => { };
Assert.IsTrue(false, "Adding a ContractCreated handler here should have failed!");
catch (InvalidOperationException ex)
Console.WriteLine(string.Format("Caught expected exception \"{0}\" when trying to add a ContractCreated handler after the first contract is generated.", ex.Message));
Console.WriteLine("All tests passed.");
public class ConfigurableContractResolver : DefaultContractResolver
readonly object contractCreatedPadlock = new object();
event EventHandler<ContractCreatedEventArgs> contractCreated;
void OnContractCreated(JsonContract contract, Type objectType)
EventHandler<ContractCreatedEventArgs> created;
lock (contractCreatedPadlock)
created = contractCreated;
created(this, new ContractCreatedEventArgs(contract, objectType));
public event EventHandler<ContractCreatedEventArgs> ContractCreated
lock (contractCreatedPadlock)
throw new InvalidOperationException("ContractCreated events cannot be added after the first contract is generated.");
contractCreated += value;
lock (contractCreatedPadlock)
throw new InvalidOperationException("ContractCreated events cannot be removed after the first contract is generated.");
contractCreated -= value;
protected override JsonContract CreateContract(Type objectType)
var contract = base.CreateContract(objectType);
OnContractCreated(contract, objectType);
public class ContractCreatedEventArgs : EventArgs
public JsonContract Contract { get; private set; }
public Type ObjectType { get; private set; }
public ContractCreatedEventArgs(JsonContract contract, Type objectType)
this.Contract = contract;
this.ObjectType = objectType;
public static class ConfigurableContractResolverExtensions
public static ConfigurableContractResolver Configure(this ConfigurableContractResolver resolver, EventHandler<ContractCreatedEventArgs> handler)
if (resolver == null || handler == null)
throw new ArgumentNullException();
resolver.ContractCreated += handler;
public static class JsonContractExtensions
const string DatePropertiesName = "_date_properties_";
public static void AddDateProperties(this JsonContract contract)
var objectContract = contract as JsonObjectContract;
if (objectContract == null)
var properties = objectContract.Properties.Where(p => p.PropertyType == typeof(DateTime) || p.PropertyType == typeof(DateTime?)).ToList();
if (properties.Count > 0)
var property = new JsonProperty
DeclaringType = contract.UnderlyingType,
PropertyName = DatePropertiesName,
UnderlyingName = DatePropertiesName,
PropertyType = typeof(string[]),
ValueProvider = new FixedValueProvider(properties.Select(p => p.PropertyName).ToArray()),
AttributeProvider = new NoAttributeProvider(),
TypeNameHandling = TypeNameHandling.None,
objectContract.Properties.Insert(0, property);
class FixedValueProvider : IValueProvider
readonly object properties;
public FixedValueProvider(object value)
#region IValueProvider Members
public object GetValue(object target)
public void SetValue(object target, object value)
throw new NotImplementedException("SetValue not implemented for fixed properties; set JsonProperty.Writable = false.");
class NoAttributeProvider : IAttributeProvider
#region IAttributeProvider Members
public IList<Attribute> GetAttributes(Type attributeType, bool inherit) { return new Attribute[0]; }
public IList<Attribute> GetAttributes(bool inherit) { return new Attribute[0]; }
public static void Main()
Console.WriteLine("Environment version: " + Environment.Version);
Console.WriteLine("Json.NET version: " + typeof(JsonSerializer).Assembly.FullName);
Console.WriteLine("Failed with unhandled exception: ");
public class AssertionFailedException : System.Exception
public AssertionFailedException() : base() { }
public AssertionFailedException(string s) : base(s) { }
public static class Assert
public static void IsTrue(bool value)
public static void IsTrue(bool value, string message)
throw new AssertionFailedException(message ?? "failed");