Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The default naming conventions for a profile should come from the glo… #4428

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 8 additions & 1 deletion src/AutoMapper/ApiCompatBaseline.txt
@@ -1,5 +1,9 @@
Compat issues with assembly AutoMapper:
CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'AutoMapper.AutoMapAttribute' changed from '[AttributeUsageAttribute(1036, AllowMultiple=true)]' in the contract to '[AttributeUsageAttribute(AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Struct, AllowMultiple=true)]' in the implementation.
CannotSealType : Type 'AutoMapper.AutoMapperConfigurationException.TypeMapConfigErrors' is actually (has the sealed modifier) sealed in the implementation but not sealed in the contract.
TypeCannotChangeClassification : Type 'AutoMapper.AutoMapperConfigurationException.TypeMapConfigErrors' is a 'struct' in the implementation but is a 'class' in the contract.
CannotSealType : Type 'AutoMapper.DuplicateTypeMapConfigurationException.TypeMapConfigErrors' is actually (has the sealed modifier) sealed in the implementation but not sealed in the contract.
TypeCannotChangeClassification : Type 'AutoMapper.DuplicateTypeMapConfigurationException.TypeMapConfigErrors' is a 'struct' in the implementation but is a 'class' in the contract.
CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.NullableContextAttribute' exists on 'AutoMapper.IMapper' in the contract but not the implementation.
CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.NullableContextAttribute' exists on 'AutoMapper.IMapper.Map(System.Object, System.Object, System.Type, System.Type, System.Action<AutoMapper.IMappingOperationOptions<System.Object, System.Object>>)' in the contract but not the implementation.
CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.NullableAttribute' exists on parameter 'opts' on member 'AutoMapper.IMapper.Map(System.Object, System.Object, System.Type, System.Type, System.Action<AutoMapper.IMappingOperationOptions<System.Object, System.Object>>)' in the contract but not the implementation.
Expand All @@ -24,6 +28,9 @@ CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.NullableAttri
CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.NullableAttribute' exists on generic param 'TDestination' on member 'AutoMapper.ResolutionContext.AutoMapper.IMapperBase.Map<TSource, TDestination>(TSource)' in the contract but not the implementation.
CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.NullableAttribute' exists on generic param 'TSource' on member 'AutoMapper.ResolutionContext.AutoMapper.IMapperBase.Map<TSource, TDestination>(TSource, TDestination)' in the contract but not the implementation.
CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.NullableAttribute' exists on generic param 'TDestination' on member 'AutoMapper.ResolutionContext.AutoMapper.IMapperBase.Map<TSource, TDestination>(TSource, TDestination)' in the contract but not the implementation.
MembersMustExist : Member 'public void AutoMapper.Configuration.MappingExpression..ctor(AutoMapper.Internal.TypePair, AutoMapper.MemberList)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public void AutoMapper.Configuration.MappingExpression<TSource, TDestination>..ctor(AutoMapper.MemberList, System.Type, System.Type)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'protected void AutoMapper.Configuration.MappingExpressionBase<TSource, TDestination, TMappingExpression>..ctor(AutoMapper.MemberList, System.Type, System.Type)' does not exist in the implementation but it does exist in the contract.
CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'AutoMapper.Configuration.Annotations.IgnoreAttribute' changed from '[AttributeUsageAttribute(384)]' in the contract to '[AttributeUsageAttribute(AttributeTargets.Field | AttributeTargets.Property)]' in the implementation.
CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'AutoMapper.Configuration.Annotations.MapAtRuntimeAttribute' changed from '[AttributeUsageAttribute(384)]' in the contract to '[AttributeUsageAttribute(AttributeTargets.Field | AttributeTargets.Property)]' in the implementation.
CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'AutoMapper.Configuration.Annotations.MappingOrderAttribute' changed from '[AttributeUsageAttribute(384)]' in the contract to '[AttributeUsageAttribute(AttributeTargets.Field | AttributeTargets.Property)]' in the implementation.
Expand All @@ -43,4 +50,4 @@ CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.NullableAttri
CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.NullableContextAttribute' exists on 'AutoMapper.QueryableExtensions.Extensions.ProjectTo<TDestination>(System.Linq.IQueryable, AutoMapper.IConfigurationProvider, System.Object, System.Linq.Expressions.Expression<System.Func<TDestination, System.Object>>[])' in the contract but not the implementation.
CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.NullableAttribute' exists on parameter 'parameters' on member 'AutoMapper.QueryableExtensions.Extensions.ProjectTo<TDestination>(System.Linq.IQueryable, AutoMapper.IConfigurationProvider, System.Object, System.Linq.Expressions.Expression<System.Func<TDestination, System.Object>>[])' in the contract but not the implementation.
CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.NullableAttribute' exists on generic param 'TDestination' on member 'AutoMapper.QueryableExtensions.Extensions.ProjectTo<TDestination>(System.Linq.IQueryable, AutoMapper.IConfigurationProvider, System.Object, System.Linq.Expressions.Expression<System.Func<TDestination, System.Object>>[])' in the contract but not the implementation.
Total Issues: 44
Total Issues: 51
53 changes: 13 additions & 40 deletions src/AutoMapper/AutoMapperMappingException.cs
Expand Up @@ -67,63 +67,37 @@ public override string StackTrace
{
return string.Join(Environment.NewLine,
base.StackTrace
.Split(new[] {Environment.NewLine}, StringSplitOptions.None)
.Split([Environment.NewLine], StringSplitOptions.None)
.Where(str => !str.TrimStart().StartsWith("at AutoMapper.")));
}
}
#endif
}
public class DuplicateTypeMapConfigurationException : Exception
public class DuplicateTypeMapConfigurationException(DuplicateTypeMapConfigurationException.TypeMapConfigErrors[] errors) : Exception
{
public TypeMapConfigErrors[] Errors { get; }

public DuplicateTypeMapConfigurationException(TypeMapConfigErrors[] errors)
public TypeMapConfigErrors[] Errors { get; } = errors;
public override string Message { get; } = GetErrors(errors);
static string GetErrors(TypeMapConfigErrors[] errors)
{
Errors = errors;
var builder = new StringBuilder();
StringBuilder builder = new();
builder.AppendLine("Duplicate CreateMap calls:");
foreach (var error in Errors)
foreach(var error in errors)
{
builder.AppendLine($"{error.Types.SourceType.FullName} to {error.Types.DestinationType.FullName} defined in profiles:");
builder.AppendLine(string.Join(Environment.NewLine, error.ProfileNames));
}
builder.AppendLine("This can cause configuration collisions and inconsistent mappings. Use a single CreateMap call per type pair.");
Message = builder.ToString();
}

public class TypeMapConfigErrors
{
public string[] ProfileNames { get; }
public TypePair Types { get; }

public TypeMapConfigErrors(TypePair types, string[] profileNames)
{
Types = types;
ProfileNames = profileNames;
}
return builder.ToString();
}

public override string Message { get; }
public readonly record struct TypeMapConfigErrors(TypePair Types, string[] ProfileNames);
}
public class AutoMapperConfigurationException : Exception
{
public TypeMapConfigErrors[] Errors { get; }
public TypePair? Types { get; }
public MemberMap MemberMap { get; set; }

public class TypeMapConfigErrors
{
public TypeMap TypeMap { get; }
public string[] UnmappedPropertyNames { get; }
public bool CanConstruct { get; }

public TypeMapConfigErrors(TypeMap typeMap, string[] unmappedPropertyNames, bool canConstruct)
{
TypeMap = typeMap;
UnmappedPropertyNames = unmappedPropertyNames;
CanConstruct = canConstruct;
}
}
public readonly record struct TypeMapConfigErrors(TypeMap TypeMap, string[] UnmappedPropertyNames, bool CanConstruct);

public AutoMapperConfigurationException(string message)
: base(message)
Expand Down Expand Up @@ -170,16 +144,15 @@ public override string Message
}
if (Errors != null)
{
var message =
new StringBuilder(
StringBuilder message = new(
"\nUnmapped members were found. Review the types and members below.\nAdd a custom mapping expression, ignore, add a custom resolver, or modify the source/destination type\nFor no matching constructor, add a no-arg ctor, add optional arguments, or map all of the constructor parameters\n");

foreach (var error in Errors)
{
var len = error.TypeMap.SourceType.FullName.Length +
error.TypeMap.DestinationType.FullName.Length + 5;

message.AppendLine(new string('=', len));
message.AppendLine(new('=', len));
message.AppendLine(error.TypeMap.SourceType.Name + " -> " + error.TypeMap.DestinationType.Name +
" (" +
error.TypeMap.ConfiguredMemberList + " member list)");
Expand Down Expand Up @@ -214,7 +187,7 @@ public override string StackTrace
if (Errors != null)
return string.Join(Environment.NewLine,
base.StackTrace
.Split(new[] { Environment.NewLine }, StringSplitOptions.None)
.Split([Environment.NewLine], StringSplitOptions.None)
.Where(str => !str.TrimStart().StartsWith("at AutoMapper."))
.ToArray());

Expand Down
7 changes: 2 additions & 5 deletions src/AutoMapper/Configuration/Annotations/AutoMapAttribute.cs
Expand Up @@ -5,12 +5,9 @@
/// Discovered during scanning assembly scanning for configuration when calling <see cref="O:AutoMapper.IMapperConfigurationExpression.AddMaps"/>
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Struct, AllowMultiple = true)]
public sealed class AutoMapAttribute : Attribute
public sealed class AutoMapAttribute(Type sourceType) : Attribute
{
public AutoMapAttribute(Type sourceType)
=> SourceType = sourceType;

public Type SourceType { get; }
public Type SourceType { get; } = sourceType;
public bool ReverseMap { get; set; }

/// <summary>
Expand Down
Expand Up @@ -7,14 +7,9 @@
/// Must be used in combination with <see cref="AutoMapAttribute" />
/// </remarks>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public sealed class MappingOrderAttribute : Attribute, IMemberConfigurationProvider
public sealed class MappingOrderAttribute(int value) : Attribute, IMemberConfigurationProvider
{
public int Value { get; }

public MappingOrderAttribute(int value)
{
Value = value;
}
public int Value { get; } = value;

public void ApplyConfiguration(IMemberConfigurationExpression memberConfigurationExpression)
{
Expand Down
Expand Up @@ -7,17 +7,12 @@
/// Must be used in combination with <see cref="AutoMapAttribute" />
/// </remarks>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public sealed class NullSubstituteAttribute : Attribute, IMemberConfigurationProvider
public sealed class NullSubstituteAttribute(object value) : Attribute, IMemberConfigurationProvider
{
/// <summary>
/// Value to use if source value is null
/// </summary>
public object Value { get; }

public NullSubstituteAttribute(object value)
{
Value = value;
}
public object Value { get; } = value;

public void ApplyConfiguration(IMemberConfigurationExpression memberConfigurationExpression)
{
Expand Down
Expand Up @@ -7,11 +7,9 @@
/// Must be used in combination with <see cref="AutoMapAttribute" />
/// </remarks>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public sealed class SourceMemberAttribute : Attribute, IMemberConfigurationProvider
public sealed class SourceMemberAttribute(string name) : Attribute, IMemberConfigurationProvider
{
public string Name { get; }

public SourceMemberAttribute(string name) => Name = name;
public string Name { get; } = name;

public void ApplyConfiguration(IMemberConfigurationExpression memberConfigurationExpression)
{
Expand Down
Expand Up @@ -8,17 +8,12 @@
/// Must be used in combination with <see cref="AutoMapAttribute" />
/// </remarks>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public sealed class ValueConverterAttribute : Attribute, IMemberConfigurationProvider
public sealed class ValueConverterAttribute(Type type) : Attribute, IMemberConfigurationProvider
{
/// <summary>
/// <see cref="IValueConverter{TSourceMember,TDestinationMember}" /> type
/// </summary>
public Type Type { get; }

public ValueConverterAttribute(Type type)
{
Type = type;
}
public Type Type { get; } = type;

public void ApplyConfiguration(IMemberConfigurationExpression memberConfigurationExpression)
{
Expand Down
Expand Up @@ -8,17 +8,12 @@
/// Must be used in combination with <see cref="AutoMapAttribute" />
/// </remarks>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public sealed class ValueResolverAttribute : Attribute, IMemberConfigurationProvider
public sealed class ValueResolverAttribute(Type type) : Attribute, IMemberConfigurationProvider
{
/// <summary>
/// <see cref="IValueResolver{TSource,TDestination,TDestMember}" /> or <see cref="IMemberValueResolver{TSource,TDestination,TSourceMember,TDestMember}" /> type
/// </summary>
public Type Type { get; }

public ValueResolverAttribute(Type type)
{
Type = type;
}
public Type Type { get; } = type;

public void ApplyConfiguration(IMemberConfigurationExpression memberConfigurationExpression)
{
Expand Down
23 changes: 9 additions & 14 deletions src/AutoMapper/Configuration/ConfigurationValidator.cs
@@ -1,6 +1,5 @@
using AutoMapper.Internal.Mappers;
namespace AutoMapper.Configuration;

[EditorBrowsable(EditorBrowsableState.Never)]
public readonly record struct ConfigurationValidator(IGlobalConfigurationExpression Expression)
{
Expand All @@ -11,7 +10,7 @@ private void Validate(ValidationContext context)
validator(context);
}
}
public void AssertConfigurationExpressionIsValid(IGlobalConfiguration config, IEnumerable<TypeMap> typeMaps)
public void AssertConfigurationExpressionIsValid(IGlobalConfiguration config, TypeMap[] typeMaps)
{
var duplicateTypeMapConfigs = Expression.Profiles.Append((Profile)Expression)
.SelectMany(p => p.TypeMapConfigs, (profile, typeMap) => (profile, typeMap))
Expand All @@ -26,25 +25,23 @@ public void AssertConfigurationExpressionIsValid(IGlobalConfiguration config, IE
}
AssertConfigurationIsValid(config, typeMaps);
}
public void AssertConfigurationIsValid(IGlobalConfiguration config, IEnumerable<TypeMap> typeMaps)
public void AssertConfigurationIsValid(IGlobalConfiguration config, TypeMap[] typeMaps)
{
var maps = typeMaps as TypeMap[] ?? typeMaps.ToArray();
var badTypeMaps =
(from typeMap in maps
(from typeMap in typeMaps
where typeMap.ShouldCheckForValid
let unmappedPropertyNames = typeMap.GetUnmappedPropertyNames()
let canConstruct = typeMap.PassesCtorValidation
where unmappedPropertyNames.Length > 0 || !canConstruct
select new AutoMapperConfigurationException.TypeMapConfigErrors(typeMap, unmappedPropertyNames, canConstruct)
).ToArray();

if (badTypeMaps.Any())
if (badTypeMaps.Length > 0)
{
throw new AutoMapperConfigurationException(badTypeMaps);
}
var typeMapsChecked = new HashSet<TypeMap>();
var configExceptions = new List<Exception>();
foreach (var typeMap in maps)
HashSet<TypeMap> typeMapsChecked = [];
List<Exception> configExceptions = [];
foreach (var typeMap in typeMaps)
{
try
{
Expand Down Expand Up @@ -81,8 +78,7 @@ private void DryRunTypeMap(IGlobalConfiguration config, HashSet<TypeMap> typeMap
return;
}
typeMapsChecked.Add(typeMap);
var context = new ValidationContext(types, memberMap, typeMap);
Validate(context);
Validate(new(types, memberMap, typeMap));
if(!typeMap.ShouldCheckForValid)
{
return;
Expand All @@ -96,8 +92,7 @@ private void DryRunTypeMap(IGlobalConfiguration config, HashSet<TypeMap> typeMap
{
throw new AutoMapperConfigurationException(memberMap.TypeMap.Types) { MemberMap = memberMap };
}
var context = new ValidationContext(types, memberMap, ObjectMapper: mapperToUse);
Validate(context);
Validate(new(types, memberMap, ObjectMapper: mapperToUse));
if (mapperToUse.GetAssociatedTypes(types) is TypePair newTypes && newTypes != types)
{
DryRunTypeMap(config, typeMapsChecked, newTypes, null, memberMap);
Expand Down