Строгий тип проверки свойств в Automapper - PullRequest
0 голосов
/ 10 января 2019

Можно ли установить какую-то глобальную конфигурацию, которая приведет к сбою процесса сопоставления или проверки, если некоторые свойства сопоставленных объектов имеют одно и то же имя, но имеют разные типы?

Типы источника / назначения

public class UserData1
{
    public int Id { get; set; }
}

public class UserData2
{
    public string Id { get; set; }
}

Отображение конфигурации

Mapper.Initialize(cfg =>
{
    cfg.CreateMap<UserData1, UserData2>();
});

Ожидаемое поведение

Либо AssertConfigurationIsValid, либо Map должны вызывать какое-то исключение проверки, если типы свойств сопоставления не совпадают.

Фактическое поведение

свойство int сопоставляется со строкой без исключения.

Шаги для воспроизведения

// Passes OK
 Mapper.Configuration.AssertConfigurationIsValid();

 // Mapping is successful
 var user2 = Mapper.Map<UserData2>(new UserData1 { Id = 156 });

Ответы [ 2 ]

0 голосов
/ 10 августа 2019

Используя ответ Артема в качестве вдохновения, я написал модульный тест, чтобы ограничить эти неявные преобразования типов несколькими сценариями, с которыми у нас все в порядке.

Подход заключается в том, чтобы найти все сопоставления свойств, которые не имеют явного сопоставления, и отфильтровать несколько сценариев, которые мы хотим разрешить.

тест XUnit:

        [Fact]
        public void AllMappedPropertiesAreSameTypeOrAreMappedExplicitly()
        {
            ServiceCollection theCollection = new ServiceCollection();

            theCollection.AddMssAutoMapper();

            IMapper theMapper = BuildProductionMapper();

            //Store all explicit mappings for easy lookup
            System.Collections.Generic.HashSet<(Type SourceType, Type DestType)> theExplicitMappings =
                theMapper.ConfigurationProvider.GetAllTypeMaps()
                .Select( map => (map.SourceType, map.DestinationType) )
                .ToHashSet();

            var theIllegalMaps =
            from typeMap in theMapper.ConfigurationProvider.GetAllTypeMaps()
            from propMap in typeMap.PropertyMaps
            let sourceType = propMap.SourceType
            let destType = propMap.DestinationType
            let bothTypes = new[] { sourceType, destType }
            where sourceType != null && destType != null
            where sourceType != destType

            //Anything that's explicitly mapped is permitted
            where !theExplicitMappings.Contains( (sourceType, destType) )

            //enums to string and vice versa is permitted
            where !( sourceType.IsEnum || sourceType == typeof( string ) && destType.IsEnum || destType == typeof( string ) )

            //mapping from one collection to another is okay
            where !bothTypes.All( type => type.IsAssignableTo( typeof( IEnumerable ) ) )
            select new
            {
                SourceType = typeMap.SourceType,
                DestinationType = typeMap.DestinationType,
                SourceMemberName = propMap.SourceMember.Name,
                DestMemberName = propMap.DestinationMember.Name,
                SourceMemberType = sourceType,
                DestinationMemberType = destType
            };
            var illegalMapsList = theIllegalMaps.ToList();
            foreach( var illegalMap in illegalMapsList )
            {
                Console.Out.WriteLine( $"Found disallowed property mapping from '{illegalMap.SourceType}.{illegalMap.SourceMemberName}' to '{illegalMap.DestinationType}.{illegalMap.DestMemberName}'" );
                Console.Out.WriteLine( $"Property name: {illegalMap.SourceMemberName}" );
                Console.Out.WriteLine( $"implicit mapping from {illegalMap.SourceMemberType} to {illegalMap.DestinationMemberType} is not allowed." );
                Console.Out.WriteLine( $"Please map these types explicitly." );
            }

            if( illegalMapsList.Any() )
            {
                throw new Exception( "One or more ambiguous mappings were found that need to be handled explicitly.  See console output for details." );
            }
        }
0 голосов
/ 10 января 2019

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

Примерно так:

Mapper.Initialize(cfg => {
    cfg.CreateMap<UserData1, UserData2>();
    ...
    cfg.ForAllMaps((typeMap, mappingExpr) =>
    {
        foreach (var map in typeMap.PropertyMaps) {
            var sourcePropInfo = map.SourceMember as PropertyInfo;
            var destPropInfo = map.DestinationMember as PropertyInfo;

            if (sourcePropInfo == null || destPropInfo == null) continue;

            if (sourcePropInfo.PropertyType != destPropInfo.PropertyType)
                throw new Exception("Wrong property type!");
        }
    });
});

В качестве ссылки был использован этот старый пост и обновлен для работы с новой версией automapper. https://stackoverflow.com/a/38080647/1703620

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...