Automapper中属性的严格类型验证

时间:2019-01-10 13:35:31

标签: c# .net serialization automapper

当映射对象的某些属性具有相同的名称但具有不同的类型时,是否可以设置某种导致映射或验证过程失败的全局配置?

来源/目标类型

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 :(得分:0)

没有可用的内置解决方案,但是可以使用自定义配置来实现。

类似这样的东西:

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

答案 1 :(得分:0)

利用Artyom的答案作为启发,我编写了一个单元测试,以将这些隐式类型转换限制在我们可以接受的几种情况下。

该方法是查找所有没有显式映射的属性映射,并过滤掉我们要允许的几种方案。

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." );
            }
        }