2

How would I need to configure AutoMapper to be able to convert a DataTable containing columns "C" and "D" to a list of MyClass by using the JsonProperty attribute for mapping?

public class MyClass
{
     [JsonProperty("C")]
     public string A { get; set; }
     [JsonProperty("D")]
     public string B { get; set; }
}
0

1 Answer 1

2

Using metadata from Json.NET's own contract resolver you can configure a name mapping from an IDataRecord to properties of your type MyClass. Having done that, you can map from any IDataReader including the one returned by DataTable.CreateDataReader() to a list of instances of your type.

First add the following extension method:

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 PropertyName in reader to UnderlyingName in TDestination
            map.ForMember(p.UnderlyingName, opt => opt.MapFrom(r => r[p.PropertyName]));
        }
    }
}

Now you can configure a MapperConfiguration and map your table to a List<MyClass> as follows:

var config = new MapperConfiguration(cfg =>
{
    cfg.CreateJsonDataReaderMap<MyClass>();
});
var mapper = config.CreateMapper();
using var reader = table.CreateDataReader();
var result = mapper.Map<List<MyClass>>(reader);

Notes:

  • Error handling for properties present in the table but not in the class, or vice versa, has not been implemented, but presumably could be.

  • If your table was created using camel-cased column names you can pass an instance of CamelCasePropertyNamesContractResolver as the second argument to CreateJsonDataReaderMap() and names should map correctly.

Demo fiddle here which uses AutoMapper version 9.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.