using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization.Formatters;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Collections.ObjectModel;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
using AutoMapper.Configuration;
public partial class MyClass
public string A { get; set; }
public string B { get; set; }
public long LongNumber { get; set; }
public int IntNumber { get; set; }
public short ShortNumber { get; set; }
public string IgnoreMe { get; set; }
public static class AutomapperJsonExtensions
static readonly IContractResolver defaultResolver = new JsonSerializer().ContractResolver;
public static void CreateJsonDataReaderMap<TDestination>(this IMapperConfigurationExpression cfg, IContractResolver resolver = null)
resolver = resolver ?? defaultResolver;
var contract = resolver.ResolveContract(typeof(TDestination)) as JsonObjectContract ?? throw new ArgumentException(string.Format("{0} is not a JSON object.", typeof(TDestination)));
var map = cfg.CreateMap<IDataRecord, TDestination>();
foreach (var p in contract.Properties.Where(p => !p.Ignored && p.Writable))
map.ForMember(p.UnderlyingName, opt => opt.MapFrom(r => r[p.PropertyName] ));
public static void Test()
new MyClass { A = "a1", B = "b1", LongNumber = 1, IntNumber = 1, ShortNumber = 1 },
new MyClass { A = "a2", B = "b2", LongNumber = long.MaxValue, IntNumber = int.MaxValue, ShortNumber = short.MaxValue },
var json = JsonConvert.SerializeObject(inputs, Formatting.Indented);
var table = JsonConvert.DeserializeObject<DataTable>(json);
var config = new MapperConfiguration(cfg =>
cfg.CreateJsonDataReaderMap<MyClass>();
var mapper = config.CreateMapper();
using var reader = table.CreateDataReader();
var result = mapper.Map<List<MyClass>>(reader);
Assert.AreEqual(result.Count, inputs.Length);
var newJson = JsonConvert.SerializeObject(result, Formatting.Indented);
Assert.IsTrue(JToken.DeepEquals(JToken.Parse(json), JToken.Parse(newJson)));
Assert.Throws<ArgumentException>(() => new MapperConfiguration(cfg => cfg.CreateJsonDataReaderMap<string>()));
Assert.Throws<ArgumentException>(() => new MapperConfiguration(cfg => cfg.CreateJsonDataReaderMap<List<MyClass>>()));
public static void Main()
Console.WriteLine("Environment version: {0} ({1})", System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription , GetNetCoreVersion());
Console.WriteLine("{0} version: {1}", typeof(JsonSerializer).Assembly.GetName().Name, typeof(JsonSerializer).Assembly.FullName);
Console.WriteLine("{0} version: {1}", typeof(MapperConfiguration).Assembly.GetName().Name, typeof(MapperConfiguration).Assembly.FullName);
Console.WriteLine("Failed with unhandled exception: ");
public static string GetNetCoreVersion()
var assembly = typeof(System.Runtime.GCSettings).GetTypeInfo().Assembly;
var assemblyPath = assembly.CodeBase.Split(new[] { '/', '\\' }, StringSplitOptions.RemoveEmptyEntries);
int netCoreAppIndex = Array.IndexOf(assemblyPath, "Microsoft.NETCore.App");
if (netCoreAppIndex > 0 && netCoreAppIndex < assemblyPath.Length - 2)
return assemblyPath[netCoreAppIndex + 1];