EmitMapper — общее сопоставление объекта абстрактной модели с абстрактным DTO.

Мне нужна помощь в переходе с ValueInjecter на EmitMapper (я решил так из соображений производительности). Мой вариант использования — один из самых распространенных: сопоставление объекта модели с 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<>, я подумал, что могу использовать метод DefaultMapConfig.ConvertGeneric EmitMapper, но я просто не могу понять, как это сделать.

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

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  

EDIT: это пример объектов, которые я хотел бы сопоставить.

//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; }
}

person faloi    schedule 31.05.2014    source источник
comment
Что это за строка: DTOInjectorTest.cs:line 334?   -  person keiv.fly    schedule 01.06.2014
comment
Не перед моим компьютером прямо сейчас, но это будет мой тест. Что-то, что заканчивается вызовом метода Map EmitMapper   -  person faloi    schedule 01.06.2014


Ответы (1)


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

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

person Omu    schedule 12.12.2014