EmitMapper - Общее отображение из абстрактного объекта модели в абстрактный DTO

Мне нужна помощь в переходе с ValueInjecter на EmitMapper (я решил по соображениям производительности). Мой пример использования - один из самых распространенных: сопоставление объекта Model с DTO на основе некоторых правил.

Одно из таких правил: если тип свойства является подклассом DomainObject, то его следует сопоставить с соответствующим DTO. С конкретными типами это нормально, но я также хочу, чтобы он работал с абстрактными типами. Проблема в том, что я не знаю, как сообщить EmitMapper, какой DTO следует использовать динамически.

В коде ValueInjecter:

public bool IsDomainObjectAndTargetIsDto(ConventionInfo it) 
{
    return it.SourceProp.Value.IsNotNull()
        && typeof(DomainObject).IsAssignableFrom(it.SourceProp.Type)
        && it.TargetProp.Type.Name.EndsWith("DTO");
}

Как все мои DTO реализует DTO<> интерфейс, я думал, что мог бы использовать EmitMapper's DefaultMapConfig.ConvertGeneric метод, но я просто не могу понять, как.

Просто для полноты я включаю свой текущий (не работающий) код:

public class ModelToDtoConventions() 
{
    public IMappingConfigurator GetConfig() 
    {
        return new DefaultMapConfig()
            .ConvertUsing<IdentificableObject, int>(o => o.Id)
            .ConvertGeneric(
                typeof (DomainObject), 
                typeof (DTO<>),
                new DefaultCustomConverterProvider(
                    typeof (DomainObjectToDtoConverter<>)
                )
            );
    }
}

public class DomainObjectToDtoConverter<TDomainObject>
{
    public DTO<TDomainObject> Convert(TDomainObject from, object state)
    {
        return (DTO<TDomainObject>)this.CreateDtoFor(@from);
    }

    private object CreateDtoFor(object modelObject)
    {
        var modelType = modelObject.GetType();
        var dtoInterface = typeof(DTO<>).MakeGenericType(modelType);

        var dtoType = dtoInterface
            .GetConcreteSubtypes()
            .Single();

        return Activator.CreateInstance(dtoType);
    }
}

Когда я пытаюсь использовать это отображение в тесте, я получаю следующее исключение

'MyProject.WebApi.Test.Utils.DTOInjectorTest.Abstract_DTO_property_of_DTO_can_be_mapped_from_its_model' failed: System.ArgumentException : Cannot bind to the target method because its signature or security transparency is not compatible with that of the delegate type.
    at System.Delegate.CreateDelegate(Type type, Object firstArgument, MethodInfo method, Boolean throwOnBindFailure)
    at System.Delegate.CreateDelegate(Type type, Object firstArgument, MethodInfo method)
    at EmitMapper.MappingConfiguration.MapConfigBaseImpl.GetGenericConverter(Type from, Type to)
    at EmitMapper.MappingConfiguration.MapConfigBaseImpl.FilterOperations(Type from, Type to, IEnumerable`1 operations)
    at EmitMapper.MappingConfiguration.DefaultMapConfig.GetMappingOperations(Type from, Type to)
    at EmitMapper.EmitBuilders.MappingBuilder.BuildCopyImplMethod()
    at EmitMapper.ObjectMapperManager.BuildObjectsMapper(String MapperTypeName, Type from, Type to, IMappingConfigurator mappingConfigurator)
    at EmitMapper.ObjectMapperManager.GetMapperInt(Type from, Type to, IMappingConfigurator mappingConfigurator)
    at EmitMapper.ObjectMapperManager.GetMapperImpl(Type from, Type to, IMappingConfigurator mappingConfigurator)
    at MyProject.WebApi.Adapters.DTOInjector.Transform[TDestination](IMappingConfigurator config, Object source, TDestination destination) in c:\Users\faloi\Documents\GitHub\api\WebApi\Adapters\DTOInjector.cs:line 56
    at MyProject.WebApi.Adapters.DTOInjector.CreateDto[TDTO](Object entity) in c:\Users\faloi\Documents\GitHub\api\WebApi\Adapters\DTOInjector.cs:line 47
    at MyProject.WebApi.Test.Utils.DTOInjectorTest.Abstract_DTO_property_of_DTO_can_be_mapped_from_its_model() in c:\Users\faloi\Documents\GitHub\api\WebApi.Test\Utils\DTOInjectorTest.cs:line 334 c:\Users\faloi\Documents\GitHub\api\WebApi\Adapters\DTOInjector.cs  56  

РЕДАКТИРОВАТЬ: это пример объектов, которые я хотел бы отобразить.

//Domain objects
public class Game
{
    public IEnumerable<Map> Maps { get; set; }
    public Map MostPlayedMap { get; set; }

    public Game()
    {
        this.Maps = new List<Map>();
    }
}

public abstract class Map : DomainObject
{
    public string Name { get; set; }
}

public class BombDefuseMap : Map
{
    public Player BombHolder { get; set; }
}

public class HostageRescueMap : Map
{
    public int QuantityOfHostages { get; set; }
}

//DTOs
public class GameDTO : DTOWithId<Game>
{
    public List<MapDTO> Maps { get; set; }
    public MapDTO MostPlayedMap { get; set; }
}

public abstract class MapDTO
{
    public string Name { get; set; }
}

public class BombDefuseMapDTO : MapDTO, DTO<BombDefuseMap>
{
    public int BombHolder { get; set; }
}

public class HostageRescueMapDTO : MapDTO, DTO<HostageRescueMap>
{
    public int QuantityOfHostages { get; set; }
}

1 ответ

Если вы беспокоитесь о производительности, взгляните на эту страницу: http://valueinjecter.codeplex.com/wikipage?title=SmartConventionInjection

это инъекции, которые работают намного лучше, но вы не получаете значение в алгоритме сопоставления, в большинстве случаев вам все равно это не нужно

Другие вопросы по тегам