We have an old (hand-cranked) system that uses reflection to map one model with another. This uses Attributes on the models to work out what needs to be transmitted. This conversion is handled at runtime inside a base class in a shared project.
I'm looking into replacing this at the lower level with an implementation of Automapper - during testing this appears to be significantly faster at high volume.
What I'd like to do, is continue to use the legacy mechanism to generate the map to maintain consistency. I can do this using the below code successfully:
public static IMapper CreateMap()
{
var configuration = new MapperConfiguration(
BuildMapForModel<ModelA, ModelB>);
var map = configuration.CreateMapper();
return map;
}
public static void BuildMapForModel<TIn, TOut>(IMapperConfigurationExpression config)
{
var expression = config.CreateMap<TIn, TOut>();
//Build the mapping with reflection.
foreach (var propertyInfo in typeof(TOut).GetProperties())
{
var attribute = propertyInfo.GetCustomAttribute(typeof(CustomMappingAttribute)) as CustomMappingAttribute;
if (attribute == null)
{
expression.ForMember(propertyInfo.Name, opt => opt.Ignore());
}
else
{
var sourceproperty = attribute.SourcePropertyName;
expression.ForMember(propertyInfo.Name, map => map.MapFrom(sourceproperty));
}
}
expression.ReverseMap();
}
This works fine. However it relies on building the mapping every time, for each class. Instead, I'd like to make the MapperConfiguration
object static, so that it can be reused repeatedly. Additionally, I'd like to be able to add to the mapping list as required.
i.e. when my code requests a mapping between ModelA and ModelB, i'd like to determine if I already have a map for that and, if not, run through the code to map it.
private static MapperConfiguration Configuration { get; set; }
public static TOut Convert<TIn, TOut>(TIn item)
{
if (Configuration == null)
{
//Create a new configuration object.
}
if (Configuration.FindTypeMapFor<TIn, TOut>() == null)
{
//Add a mapping to the configuration - via BuildMapForModel.
}
var map = Configuration.CreateMapper();
return map.Map<TIn, TOut>(item);
}
However, MapperConfiguration
doesn't appear to allow adding of mappings once created, nor does it seem to allow a parameterless constructor.
How can I set it up so that I run the mapping code only when necessary, but avoid having to run it each and every time?