Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
9d2dfd9
consider member value resolvers and value converters for source valid…
lbargaoanu Jun 29, 2022
29f1beb
simplify
lbargaoanu Jun 29, 2022
8552e2e
re-enable configuration only tests
lbargaoanu Jun 30, 2022
18c7f73
try to cover all cases
lbargaoanu Jul 1, 2022
704e5ba
cosmetic
lbargaoanu Jul 6, 2022
ba60290
polymorphic implementation for type converters
lbargaoanu Jul 6, 2022
7eff43f
remove ConstructDestinationUsingServiceLocator
lbargaoanu Jul 7, 2022
3c2ec11
simplify
lbargaoanu Jul 7, 2022
884e22a
remove TypeMap.AsProxy
lbargaoanu Jul 7, 2022
a2c4ba0
remove DestinationTypeToUse
lbargaoanu Jul 7, 2022
42ef755
code reuse
lbargaoanu Jul 7, 2022
821d4fa
add MemberMap.Resolver
lbargaoanu Jul 8, 2022
c38b3dc
code reuse
lbargaoanu Jul 8, 2022
ed3ac6e
Resolver.GetSourceMember
lbargaoanu Jul 8, 2022
99092f4
ClassValueResolver
lbargaoanu Jul 8, 2022
2fa05d6
FuncResolver
lbargaoanu Jul 8, 2022
ce51167
ExpressionResolver
lbargaoanu Jul 8, 2022
8ce0961
remove storage for CustomCtorExpression
lbargaoanu Jul 8, 2022
40cecce
remove storage for TypeMap.CustomMapExpression
lbargaoanu Jul 8, 2022
6cd3631
cosmetic
lbargaoanu Jul 8, 2022
854fa31
implement the convention based resolver in MemberMap
lbargaoanu Jul 9, 2022
1eab5f1
implement CanResolveValue in MemberMap
lbargaoanu Jul 9, 2022
787ae9d
cosmetic
lbargaoanu Jul 9, 2022
9b872ef
remove TypeMap.IsValid
lbargaoanu Jul 10, 2022
63aeef3
DestinationTypeOverride is considered separately
lbargaoanu Jul 10, 2022
c366182
cosmetic
lbargaoanu Jul 10, 2022
8d87e4e
MemberMapDetails
lbargaoanu Jul 10, 2022
20e379d
TypeMapDetails
lbargaoanu Jul 10, 2022
a1c02c7
cosmetic
lbargaoanu Jul 10, 2022
415c1d4
remove TypeMap._orderedPropertyMaps
lbargaoanu Jul 11, 2022
8b733b1
cosmetic
lbargaoanu Jul 11, 2022
999d65f
reuse the constructor map object
lbargaoanu Jul 12, 2022
79fd635
cosmetic
lbargaoanu Jul 12, 2022
449a50b
remove QueryMapperVisitor
lbargaoanu Jul 13, 2022
5b0cf17
hard code the map based projection mappers
lbargaoanu Jul 14, 2022
6fdc82b
IPojectionMapper.IsMatch(TypePair context)
lbargaoanu Jul 15, 2022
ddc934f
cosmetic
lbargaoanu Jul 15, 2022
798ebf2
constructor parameters default values with ProjectTo
lbargaoanu Jul 17, 2022
6024cf3
remove ResolutionContext.Options
lbargaoanu Jul 18, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
consider member value resolvers and value converters for source valid…
…ation
  • Loading branch information
lbargaoanu committed Jun 29, 2022
commit 9d2dfd97c3474e38b75ebd8dbbdf06a257115bf3
5 changes: 4 additions & 1 deletion src/AutoMapper/MemberMap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ public class MemberMap
public virtual ValueResolverConfiguration ValueResolverConfig { get => default; set { } }
public virtual ValueResolverConfiguration ValueConverterConfig { get => default; set { } }
public virtual IReadOnlyCollection<ValueTransformerConfiguration> ValueTransformers => Array.Empty<ValueTransformerConfiguration>();
public MemberInfo SourceMember => CustomMapExpression.GetMember() ?? SourceMembers.LastOrDefault();
public MemberInfo SourceMember => CustomMapExpression.GetMember() ?? SourceMembers.FirstOrDefault();
public string GetSourceMemberName() =>
ValueConverterConfig?.GetSourceMemberName() ?? ValueResolverConfig?.GetSourceMemberName() ?? SourceMember?.Name;
public bool MustUseDestination => UseDestinationValue is true || !CanBeSet;
public void MapFrom(LambdaExpression sourceMember)
{
Expand Down Expand Up @@ -92,6 +94,7 @@ public ValueResolverConfiguration(object instance, Type interfaceType)
InterfaceType = interfaceType;
}
public Type ResolvedType => InterfaceType.GenericTypeArguments.Last();
public string GetSourceMemberName() => SourceMember == null ? SourceMemberName : SourceMember.GetMember()?.Name;
}
public readonly struct ValueTransformerConfiguration
{
Expand Down
19 changes: 3 additions & 16 deletions src/AutoMapper/TypeMap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -176,41 +176,28 @@ private void AddPropertyMap(PropertyMap propertyMap)
}
public string[] GetUnmappedPropertyNames()
{
var autoMappedProperties = GetPropertyNames(PropertyMaps);
IEnumerable<string> properties;
if (ConfiguredMemberList == MemberList.Destination)
{
properties = Profile.CreateTypeDetails(DestinationType).WriteAccessors
.Select(p => p.Name)
.Where(p => !ConstructorParameterMatches(p))
.Except(autoMappedProperties)
.Except(MappedMembers().Select(m => m.DestinationName))
.Except(PathMaps.Select(p => p.MemberPath.First.Name));
}
else
{
var redirectedSourceMembers = MemberMaps
.Where(pm => pm.IsMapped && pm.SourceMember != null && pm.SourceMember.Name != pm.DestinationName)
.Select(pm => pm.SourceMember.Name);

var ignoredSourceMembers = _sourceMemberConfigs?.Values
.Where(smc => smc.IsIgnored())
.Select(pm => pm.SourceMember.Name);

properties = Profile.CreateTypeDetails(SourceType).ReadAccessors
.Select(p => p.Name)
.Except(autoMappedProperties)
.Except(redirectedSourceMembers)
.Except(MappedMembers().Select(m => m.GetSourceMemberName()))
.Except(ignoredSourceMembers ?? Array.Empty<string>());
}
return properties.Where(memberName => !Profile.GlobalIgnores.Any(memberName.StartsWith)).ToArray();
string GetPropertyName(PropertyMap pm) => ConfiguredMemberList == MemberList.Destination
? pm.DestinationName
: pm.SourceMembers.Length > 1
? pm.SourceMembers[0].Name
: pm.SourceMember?.Name ?? pm.DestinationName;
string[] GetPropertyNames(IEnumerable<PropertyMap> propertyMaps) => propertyMaps.Where(pm => pm.IsMapped).Select(GetPropertyName).ToArray();
IEnumerable<MemberMap> MappedMembers() => MemberMaps.Where(pm => pm.IsMapped);
}

public PropertyMap FindOrCreatePropertyMapFor(MemberInfo destinationProperty, Type destinationPropertyType)
{
var propertyMap = GetPropertyMap(destinationProperty.Name);
Expand Down
5 changes: 3 additions & 2 deletions src/UnitTests/BasicFlattening.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
using System.Collections.Generic;
using Xunit;
using Shouldly;

using System.Linq;

namespace AutoMapper.UnitTests
{
public class BasicFlattening : AutoMapperSpecBase
Expand Down Expand Up @@ -232,6 +233,6 @@ public class CustomerDTO
protected override MapperConfiguration CreateConfiguration() => new(cfg => cfg.CreateMap<Customer, CustomerDTO>(MemberList.Source).ForMember(d=>d.Id, o=>o.MapFrom(s=>s.AnotherId)));
[Fact]
public void Should_validate() =>
new Action(AssertConfigurationIsValid).ShouldThrowException<AutoMapperConfigurationException>(ex => ex.Errors[0].UnmappedPropertyNames[0].ShouldBe(nameof(Address.Id)));
new Action(AssertConfigurationIsValid).ShouldThrow<AutoMapperConfigurationException>().Errors.Single().UnmappedPropertyNames.Single().ShouldBe(nameof(Address.Id));
}
}
43 changes: 43 additions & 0 deletions src/UnitTests/ConfigurationValidation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,49 @@ public void Should_fail_a_configuration_check()
{
typeof(AutoMapperConfigurationException).ShouldBeThrownBy(AssertConfigurationIsValid);
}
}

public class ResolversWithSourceValidation : AutoMapperSpecBase
{
class Source
{
public int Resolved { get; set; }
public int TypedResolved { get; set; }
public int Converted { get; set; }
public int TypedConverted { get; set; }
}
class Destination
{
public int ResolvedDest { get; set; }
public int TypedResolvedDest { get; set; }
public int ConvertedDest { get; set; }
public int TypedConvertedDest { get; set; }
}
class MemberResolver : IMemberValueResolver<Source, Destination, int, int>
{
public int Resolve(Source source, Destination destination, int sourceMember, int destinationMember, ResolutionContext context) => 5;
}
class ValueConverter : IValueConverter<int, int>
{
public int Convert(int sourceMember, ResolutionContext context) => 5;
}
protected override MapperConfiguration CreateConfiguration() => new(cfg =>
{
cfg.CreateMap<Source, Destination>(MemberList.Source)
.ForMember(d => d.ResolvedDest, o => o.MapFrom<MemberResolver, int>("Resolved"))
.ForMember(d=>d.TypedResolvedDest, o => o.MapFrom<MemberResolver, int>(s => s.TypedResolved))
.ForMember(d => d.ConvertedDest, o => o.ConvertUsing<ValueConverter, int>("Converted"))
.ForMember(d => d.TypedConvertedDest, o => o.ConvertUsing<ValueConverter, int>(s => s.TypedConverted));
});
[Fact]
public void Should_work()
{
var result = Mapper.Map<Source, Destination>(new Source());
result.ResolvedDest.ShouldBe(5);
result.TypedResolvedDest.ShouldBe(5);
result.ConvertedDest.ShouldBe(5);
result.TypedConvertedDest.ShouldBe(5);
}
}

public class NonMemberExpressionWithSourceValidation : NonValidatingSpecBase
Expand Down