Как передать аргументы конструктору базового профиля сопоставления?

В настоящее время я переношу несколько профилей сопоставления с Automapper 4.2.1 на последнюю версию 9.0.0. Старые профили сопоставления строятся иерархически, где абстрактный базовый класс требует аргумента типа IDatetime. Эта инъекция используется только для тестирования.

public abstract MappingProfileBase : Profile 
{
    protected MappingProfileBase(IDatetime datetime)
    {
        this.CreateMap<Foo, FooDto>()
            .ForMember(dest => dest.SomeTimeStamp, opt => opt.MapFrom(src => datetime));
            // Further mappings 
    }
}

public MappingProfileA : MappingProfileBase
{
    public MappingProfileA(IDatetime datetime) : base(datetime)
    {
        this.CreateMap<FooDerived, FooDerivedDto>()        
            // Further and more specific mappings 
    }   
}

Теперь я хотел бы перейти к новым методам Include и IncludeBase<> и отменить наследование MappingProfileA и MappingProfileBase, но просто не знаю, как быть с внедренным интерфейсом. Ни один из новых методов не принимает никаких аргументов.

Вот как я думаю, что это должно выглядеть так:

public class MappingProfileBase : Profile
{
    public MappingProfileBase(IDatetime datetime)
    {
        this.CreateMap<Foo, FooDto>()
            .ForMember(dest => dest.SomeTimeStamp, opt => opt.MapFrom(src => datetime));
            // Further mappings
    }
}

public class MappingProfileA : Profile
{
    public MappingProfileA()
    {
        this.CreateMap<FooDerived, FooDerivedDto>();
            .IncludeBase<Foo, FooDto>();
    }
}

Итак, как я могу передать аргументы конструктору класса base? Какие еще возможности существуют?


person Matthias Güntert    schedule 22.10.2019    source источник
comment
docs.automapper.org/en/latest/Dependency-injection.html   -  person Lucian Bargaoanu    schedule 22.10.2019


Ответы (1)


Спасибо (еще раз) Люциану. Я решил эту проблему, предоставив профиль экземпляр для AddProfile (вместо Type) с помощью Autofac. Поэтому я должен был заранее зарегистрировать конкретный тип контейнера.

private static MapperConfiguration GetMappingConfiguration()
{
    var containerBuilder = new ContainerBuilder();
    containerBuilder.RegisterType<DateTime>().As<IDateTime>();

    var assembly = Assembly.GetExecutingAssembly();
    var loadedProfiles = assembly.ExportedTypes
        .Where(type => type.IsSubclassOf(typeof(Profile)))
        .ToArray();

    containerBuilder.RegisterTypes(loadedProfiles);

    var container = containerBuilder.Build();

    var config = new MapperConfiguration(cfg =>
    {
        cfg.ConstructServicesUsing(container.Resolve);

        foreach (var profile in loadedProfiles)
        {
            var resolvedProfile = container.Resolve(profile) as Profile;
            cfg.AddProfile(resolvedProfile);
        }
    });

    return config;
}

Вот два примера профилей:

public class BaseMappingProfile : Profile
{
    public BaseMappingProfile(IDateTime datetime)
    {
        this.CreateMap<Foo, FooDto>()
            .ForMember(d => d.Timestamp, o => o.MapFrom(s => datetime))
            .ForMember(d => d.PropertyA, o => o.MapFrom(s => s.Property1));
    }
}

public class FooMappingProfile : Profile
{
    public FooMappingProfile()
    {
        this.CreateMap<FooDerived, FooDerivedDto>()
            .IncludeBase<Foo, FooDto>()
            .ForMember(d => d.PropertyB, o => o.MapFrom(s => s.Property2));
    }
}

А затем из модульного теста:

[Fact]
public void Should_Map_From_Foo_To_FooDto()
{
    var config = GetMappingConfiguration();
    var mapper = config.CreateMapper();

    var foo = new Foo {Property1 = "I am property 1"};
    var fooDto = mapper.Map<FooDto>(foo);

    // Asserts...
}

Конечно, статический метод GetMappingConfiguration требует дальнейшей модификации. Но в принципе работает.

Преимущество использования IncludeBase заключается в отсутствии дублирования кода. Но с другой стороны, более сложные профили и настройка тестов, особенно в этом случае.

person Matthias Güntert    schedule 22.10.2019
comment
Почему бы просто не ввести что-то в распознаватель? Профиль — это синглтон, и это может быть проблематично. - person Lucian Bargaoanu; 22.10.2019