Reputation: 8224
I'm trying to use AutoMapper (v6.1.1) to flatten out a class containing further nested classes.
For reasons™ I'm unable to alter these classes, so altering names is not possible.
Bearing this in mind I can solve it using the static Mapper like so:
// This is the nested user, it has a further nested class
public class NestedUser
{
public long id { get; set; }
public string type { get; set; }
public Attributes attributes { get; set; }
}
public class Attributes
{
public string first_name { get; set; }
public string last_name { get; set; }
public string name { get; set; }
}
// This is the flattened representation
public class FlattenedUser
{
public long id { get; set; }
public string type { get; set; }
public string first_name { get; set; }
public string last_name { get; set; }
public string name { get; set; }
}
// Create a nested user
var nested = new NestedUser
{
id = 1,
type = "Contact",
attributes = new Attributes
{
first_name = "Equals",
last_name = "Kay",
name = "Equalsk"
}
};
// Use the static Mapper to flatten
Mapper.Initialize(cfg =>
{
cfg.CreateMap<Attributes, FlattenedUser>(MemberList.None);
cfg.CreateMap<NestedUser, FlattenedUser>(MemberList.None)
.ConstructUsing(s => Mapper.Map<FlattenedUser>(s.attributes));
});
Mapper.AssertConfigurationIsValid();
var flattened = Mapper.Map<FlattenedUser>(nested);
The object flattened
now has all of its properties correctly populated.
For more reasons™ I want to use an instance of AutoMapper, something like this:
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<Attributes, FlattenedUser>(MemberList.None);
cfg.CreateMap<NestedUser, FlattenedUser>(MemberList.None)
.ConstructUsing(s => Mapper.Map<FlattenedUser>(s.attributes));
});
config.AssertConfigurationIsValid();
var flattened = config.CreateMapper().Map<FlattenedUser>(nested);
My issue is the line .ConstructUsing(s => ... ));
, it refers to the static Mapper and so it throws a runtime exception:
System.InvalidOperationException: 'Mapper not initialized. Call Initialize with appropriate configuration. If you are trying to use mapper instances through a container or otherwise, make sure you do not have any calls to the static Mapper.Map methods, and if you're using ProjectTo or UseAsDataSource extension methods, make sure you pass in the appropriate IConfigurationProvider instance.'
I don't want to use .ForMember(...)
for each nested property as it defeats the object of what I'm trying to do.
Now I'm stuck. Is it possible to flatten out the nested class using an instance of AutoMapper as opposed to the static way?
Upvotes: 2
Views: 319
Reputation: 3651
I see 2 options to resolve the issue, depending on your case one should fit:
First: if you want to continue using static mapper for nested object than you have to move registration of nested objects to static configuration:
Mapper.Initialize(cfg=> cfg.CreateMap<Attributes, FlattenedUser>(MemberList.None));
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<NestedUser, FlattenedUser>(MemberList.None)
.ConstructUsing(s => Mapper.Map<FlattenedUser>(s.attributes));
});
Second: Use ResolutionContext
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<Attributes, FlattenedUser>(MemberList.None);
cfg.CreateMap<NestedUser, FlattenedUser>(MemberList.None)
.ConstructUsing((s, r) => r.Mapper.Map<FlattenedUser>(s.attributes));
});
Upvotes: 3