using System.Text.RegularExpressions;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
public static void Main()
""name"" : ""Joe Shmoe"",
""url"": ""http://www.someplace.com/mypicture.jpg""
""title"": ""The Godfather"",
""starring"": ""Marlon Brando"",
var serializerSettings = new JsonSerializerSettings
NullValueHandling = NullValueHandling.Ignore,
ContractResolver = new CamelCasePropertyNamesContractResolver()
serializerSettings.Converters.Add(new JsonPathConverter());
Person p = JsonConvert.DeserializeObject<Person>(json, serializerSettings);
Console.WriteLine(p.Name);
Console.WriteLine(p.Age);
Console.WriteLine(p.ProfilePicture);
Console.WriteLine(p.FavoriteMovie.Title + " (" + p.FavoriteMovie.Year + ")");
Console.WriteLine(p.FavoriteColor);
[JsonConverter(typeof(JsonPathConverter))]
public string Name { get; set; }
public int Age { get; set; }
[JsonProperty("picture.data.url")]
public string ProfilePicture { get; set; }
[JsonProperty("favorites.movie")]
public Movie FavoriteMovie { get; set; }
[JsonProperty("favorites.color")]
public string FavoriteColor { get; set; }
public string Title { get; set; }
public int Year { get; set; }
public class JsonPathConverter : JsonConverter
public override object ReadJson(
JsonSerializer serializer)
JObject jo = JObject.Load(reader);
object targetObj = Activator.CreateInstance(objectType);
foreach (PropertyInfo prop in objectType.GetProperties().Where(p => p.CanRead && p.CanWrite))
JsonPropertyAttribute att = prop.GetCustomAttributes(true)
.OfType<JsonPropertyAttribute>()
string jsonPath = att != null ? att.PropertyName : prop.Name;
if (serializer.ContractResolver is DefaultContractResolver)
var resolver = (DefaultContractResolver)serializer.ContractResolver;
jsonPath = resolver.GetResolvedPropertyName(jsonPath);
if (!Regex.IsMatch(jsonPath, @"^[a-zA-Z0-9_.-]+$"))
throw new InvalidOperationException("JProperties of JsonPathConverter can have only letters, numbers, underscores, hiffens and dots but name was '" + jsonPath + "'.");
JToken token = jo.SelectToken(jsonPath);
if (token != null && token.Type != JTokenType.Null)
object value = token.ToObject(prop.PropertyType, serializer);
prop.SetValue(targetObj, value, null);
public override bool CanConvert(Type objectType)
return objectType.GetCustomAttributes(true).OfType<JsonPathConverter>().Any();
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
var properties = value.GetType().GetRuntimeProperties().Where(p => p.CanRead && p.CanWrite);
JObject main = new JObject();
foreach (PropertyInfo prop in properties)
JsonPropertyAttribute att = prop.GetCustomAttributes(true)
.OfType<JsonPropertyAttribute>()
string jsonPath = att != null ? att.PropertyName : prop.Name;
if (serializer.ContractResolver is DefaultContractResolver)
var resolver = (DefaultContractResolver)serializer.ContractResolver;
jsonPath = resolver.GetResolvedPropertyName(jsonPath);
var nesting = jsonPath.Split('.');
JObject lastLevel = main;
for (int i = 0; i < nesting.Length; i++)
if (i == nesting.Length - 1)
lastLevel[nesting[i]] = new JValue(prop.GetValue(value));
if (lastLevel[nesting[i]] == null)
lastLevel[nesting[i]] = new JObject();
lastLevel = (JObject)lastLevel[nesting[i]];
serializer.Serialize(writer, main);