I have an existing .NET Framework 4.8 Web API project that uses AutoMapper version 7.0.1
.
I have upgraded the project to .NET 6 and the AutoMapper nuget package to version 10.1.1
.
It appears that the existing mappings no longer work as they did in version 7.0.1
.
The existing mappings class look like this:
public static class AutoMapperConfig
{
public static void CreateMaps()
{
Mapper.Initialize(cfg =>
{
CreateAccountConnectorMaps(cfg);
CreateConnectorMaps(cfg);
});
}
private static void CreateAccountConnectorMaps(IMapperConfigurationExpression cfg)
{
cfg.CreateMap<AccountConnector, AccountConnectorModel>()
.ReverseMap()
.ForMember(m => m.CustomFields, o => o.Ignore())
.ForMember(m => m.Properties, o => o.Ignore())
.ForAllMembers(IgnoreSourceValuesWithInternalOrPrivateSetters);
}
private static void CreateConnectorMaps(IMapperConfigurationExpression cfg)
{
cfg.CreateMap<Connector, ConnectorModel>()
.ForMember(d => d.Parameters, o => o.MapFrom(s => s.Parameters.Where(p =>
!p.IsPartnerProperty &&
!p.Hide &&
p.Values.None(v => ParameterValues.IsPagingParameter(v.Value)))))
.ForMember(d => d.AuthDescription, o => o.MapFrom(s => s.Authentication.FirstOrDefault(x => x.IsDefault).AuthDescription))
.ForMember(d => d.AuthType, o => o.MapFrom(s => s.Authentication.FirstOrDefault(x => x.IsDefault).AuthType))
.ForMember(d => d.OAuth2Type, o => o.MapFrom(s => s.Authentication.FirstOrDefault(x => x.IsDefault).OAuth2Type))
.ForMember(d => d.AuthScheme, o => o.MapFrom(s => s.Authentication.FirstOrDefault(x => x.IsDefault).AuthScheme))
.ForMember(d => d.IsSystemConnector, o => o.MapFrom(s => s.ProductAddon != null && s.ProductAddon.IsSystemConnector))
.ForMember(d => d.Categories, o => o.MapFrom(s => s.ProductAddon == null ? null : s.ProductAddon.Categories.Select(c => c.Category.Name)))
.ForMember(d => d.PartnerSetupGuideUrl, o => o.MapFrom(s => s.ProductAddon == null ? null : s.ProductAddon.PartnerSetupGuideUrl))
.ForMember(d => d.CustomizableCategories, o => o.MapFrom(s => s.MethodCategories == null ? null : s.MethodCategories.Where(item => item.CanCopyToAccountConnectorMethodCategory)))
.ReverseMap()
.ForAllMembers(IgnoreSourceValuesWithInternalOrPrivateSetters);
}
private static void IgnoreSourceValuesWithInternalOrPrivateSetters<TSource, TDestination, TMember>(IMemberConfigurationExpression<TSource, TDestination, TMember> member)
{
member.Condition((source, destination, sourceMember, destMember) =>
{
if (sourceMember == null)
{
return false;
}
var sourceProp = source.GetType().GetProperty(member.DestinationMember.Name);
return sourceProp?.GetSetMethod(false) != null;
});
}
}
The new mappings haven't changed except since the version upgrade the AutoMapperConfig
class now inherits from AutoMapper.Profile
.
The new mappings class looks like this:
public class AutoMapperConfig : Profile
{
public AutoMapperConfig()
{
CreateAccountConnectorMaps();
CreateConnectorMaps();
}
private void CreateAccountConnectorMaps()
{
CreateMap<AccountConnector, AccountConnectorModel>()
.ReverseMap()
.ForMember(src => src.CustomFields, opt => opt.Ignore())
.ForMember(src => src.Properties, opt => opt.Ignore())
.ForAllMembers(IgnoreSourceValuesWithInternalOrPrivateSetters);
}
private void CreateConnectorMaps()
{
CreateMap<Connector, ConnectorModel>()
.ForMember(dest => dest.Parameters, opt => opt.MapFrom(src => src.Parameters.Where(p =>
!p.IsPartnerProperty &&
!p.Hide &&
p.Values.None(v => ParameterValues.IsPagingParameter(v.Value)))))
.ForMember(dest => dest.AuthDescription, opt => opt.MapFrom(src => src.Authentication.FirstOrDefault(x => x.IsDefault).AuthDescription))
.ForMember(dest => dest.AuthType, opt => opt.MapFrom(src => src.Authentication.FirstOrDefault(x => x.IsDefault).AuthType))
.ForMember(dest => dest.OAuth2Type, opt => opt.MapFrom(src => src.Authentication.FirstOrDefault(x => x.IsDefault).OAuth2Type))
.ForMember(dest => dest.AuthScheme, opt => opt.MapFrom(src => src.Authentication.FirstOrDefault(x => x.IsDefault).AuthScheme))
.ForMember(dest => dest.IsSystemConnector, opt => opt.MapFrom(src => src.ProductAddon != null && src.ProductAddon.IsSystemConnector))
.ForMember(dest => dest.Categories, opt => opt.MapFrom(src => src.ProductAddon == null ? null : src.ProductAddon.Categories.Select(c => c.Category.Name)))
.ForMember(dest => dest.PartnerSetupGuideUrl, opt => opt.MapFrom(src => src.ProductAddon == null ? null : src.ProductAddon.PartnerSetupGuideUrl))
.ForMember(dest => dest.CustomizableCategories, opt => opt.MapFrom(src => src.MethodCategories == null ? null : src.MethodCategories.Where(mc => mc.CanCopyToAccountConnectorMethodCategory)))
.ReverseMap()
.ForAllMembers(IgnoreSourceValuesWithInternalOrPrivateSetters);
}
private void IgnoreSourceValuesWithInternalOrPrivateSetters<TSource, TDestination, TMember>(IMemberConfigurationExpression<TSource, TDestination, TMember> member)
{
member.Condition((source, destination, sourceMember, destMember) =>
{
if (sourceMember == null)
{
return false;
}
var sourceProp = source.GetType().GetProperty(member.DestinationMember.Name);
return sourceProp?.GetSetMethod(false) != null;
});
}
}
N.B. The domain entities and the models are the same across both projects.
In the Web API controller action on the existing .NET Framework Web API project when I try to map an instance of an AccountConnector
to the AccountConnectorModel
type using:
var mappedModel = Mapper.Map<AccountConnectorModel>(accountConnector);
it maps successfully.
However when I do the same on the new .NET 6 Web API project using:
var mappedModel = _mapper.Map<AccountConnectorModel>(accountConnector);
It throws a mapping exception, with 2 inner exceptions.
Outer Exception
Error mapping types.
Mapping types:
AccountConnector -> AccountConnectorModel
Domain.Connectors.AccountConnector -> Models.AccountConnectorModel
Type Map configuration:
AccountConnector -> AccountConnectorModel
Domain.Connectors.AccountConnector -> Models.AccountConnectorModel
Destination Member:
Connector
Inner Exception 1
Error mapping types.
Mapping types:
Connector -> ConnectorModel
Domain.Connectors.Connector -> Models.ConnectorModel
Type Map configuration:
Connector -> ConnectorModel
Domain.Connectors.Connector -> Models.ConnectorModel
Destination Member:
Authentication
Inner Exception 2
Missing type map configuration or unsupported mapping.
Mapping types:
ConnectorAuthentication -> ConnectorAuthenticationModel
Domain.Connectors.ConnectorAuthentication -> Models.ConnectorAuthenticationModel