Я новичок в AutoMapper, но я прочитал несколько руководств и решил попробовать. В этих учебниках была хорошая идея, которую я решил принять. Авторитет предположил, что код отображения для модели представления должен оставаться в модели представления, а не в конфигурации AutoMapper. Это сделает его более компактным и легко читаемым:
Вот основные файлы для этого, используя отражения, AutoMapperConfiguration:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using AutoMapper;
public class AutoMapperConfig
{
private Assembly assembly;
public AutoMapperConfig(Assembly assembly)
{
this.assembly = assembly;
}
public void Execute()
{
var types = this.assembly.GetExportedTypes();
LoadStandardMappings(types);
LoadCustomMappings(types);
}
private static void LoadStandardMappings(IEnumerable<Type> types)
{
var maps = from t in types
from i in t.GetInterfaces()
where i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IMapFrom<>) && !t.IsAbstract && !t.IsInterface
select new { Source = i.GetGenericArguments()[0], Destination = t };
foreach (var map in maps)
{
Mapper.CreateMap(map.Source, map.Destination);
}
}
private static void LoadCustomMappings(IEnumerable<Type> types)
{
var maps = from t in types
from i in t.GetInterfaces()
where typeof(IHaveCustomMappings).IsAssignableFrom(t) && !t.IsAbstract && !t.IsInterface
select (IHaveCustomMappings)Activator.CreateInstance(t);
foreach (var map in maps)
{
map.CreateMappings(Mapper.Configuration);
}
}
}
public interface IMapFrom<T>
{
}
public interface IHaveCustomMappings
{
void CreateMappings(IConfiguration configuration);
}
Интерфейсы IMapFrom и IHaveCustom здесь предназначены только для обозначения классов сопоставления. Теперь мы подошли к интересной части. Когда я делаю, например, класс, подобный следующему
public class BasicAddressViewModel : IHaveCustomMappings
{
public string Id { get; set; }
[Display(Name = "Name")]
public string Label { get; set; }
[Display(Name = "Number")]
public string Location { get; set; }
public void CreateMappings(IConfiguration configuration)
{
var map = configuration.CreateMap<Address, BasicAddressViewModel>();
map.ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.Id));
map.ForMember(dest => dest.Label, opt => opt.MapFrom(src => src.Label));
map.ForMember(dest => dest.Location, opt => opt.MapFrom(src => src.Location));
}
}
Я устанавливаю сопоставления в методе CreateMappings, но если я решил использовать этот класс в качестве родителя, то эти сопоставления не будут доступны для моего дочернего класса, и поэтому мне придется повторно использовать один и тот же код для всех моих дочерних классов:
public class IndexAddressViewModel : BasicAddressViewModel
{
public void CreateMappings(IConfiguration configuration)
{
var map = configuration.CreateMap<Address, IndexAddressViewModel >();
map.ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.Id));
map.ForMember(dest => dest.Label, opt => opt.MapFrom(src => src.Label));
map.ForMember(dest => dest.Location, opt => opt.MapFrom(src => src.Location));
}
}
На самом деле, чего я хочу достичь, это
public class IndexAddressViewModel : BasicAddressViewModel
{
}
Спасибо заранее за любые предложения.
Вы можете создать защищенный метод в вашем базовом классе, который создает настраиваемые сопоставления
protected virtual IMappingExpression<BasicAddressViewModel, TDestination> CreateBaseMappings<TDestination>(IMappingExpression<BasicAddressViewModel, TDestination> mappingExpression)
where TDestination : BasicAddressViewModel
и сделать virtual
метод CreateMappings(IConfiguration configuration)
virtual
чтобы вы могли override
его в производном классе и вызвать базовый метод CreateBaseMappings
который возвращает IMappingExpression<BasicAddressViewModel, TDestination>
что означает, что вы можете добавить больше сопоставлений для других участников EDIT Я нашел лучшее решение. :)
Начиная с AutoMapper 2.0 вы можете использовать IncludeBase<BaseModel, BaseViewModel>()
для вызова сопоставления для базового типа. Таким образом, новое решение - сделать ваш метод CreateMappings(IConfiguration configuration)
virtual
в базовом классе ViewModel и переопределить его в производном классе, где вы вызываете:
configuration.CreateMap().IncludeBase();