// Source
public record AuthorRequest(
string Name,
string Biography,
DateTime DateOfBirth);
// Destination
public record AuthorUpdateCommand(
Guid Id,
string Name,
string Biography,
DateTime DateOfBirth
) : AuthorCommand(Name, Biography, DateOfBirth), IRequest<Result<Updated>>;
public class AuthorProfile : Profile
{
public AuthorProfile()
{
CreateMap<(Guid Id, AuthorRequest AuthorRequest), AuthorUpdateCommand>()
.ForMember(dst => dst, opt => opt.MapFrom(src => src.AuthorRequest))
.ForMember(dst => dst.Id, opt => opt.MapFrom(src => src.Id));
}
}
I would like to do something similar that I do with the Mapster library
to create a projection between a set of tuples and convert it to AuthorUpdateCommand
. For example, I want something that, when I add a new field to AuthorRequest and AuthorUpdateCommand, I don't need to modify the mapping anymore.
Exception has occurred: CLR/System.ArgumentException
An exception of type 'System.ArgumentException' occurred in AutoMapper.dll but was not handled in user code: 'Expression 'dst => dst' must resolve to top-level member and not any child object's properties. You can use ForPath, a custom resolver on the child type or the AfterMap option instead.'
at AutoMapper.Internal.ReflectionHelper.FindProperty(LambdaExpression lambdaExpression)
at AutoMapper.Configuration.MappingExpression`2.ForMember[TMember](Expression`1 destinationMember, Action`1 memberOptions)
at CatalogContext.Application.Common.Mappings.AuthorProfile..ctor() in c:\Users\jose\Music\github\Projetos\BookVerse\CatalogContext\src\CatalogContext.Application\Common\Mappings\AuthorProfile.cs:line 16
at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean wrapExceptions)
I make a request to the controller. Just like I defined in the mapping, I am passing a tuple with Id
and AuthorRequest
. AuthorRequest
has almost the same fields, except for the Id. That's why I am trying to create a projection.
public record AuthorRequest(
string Name,
string Biography,
DateTime DateOfBirth);
[HttpPut("{id:guid}")]
public async Task<IActionResult> Update(Guid id, AuthorRequest request)
{
var command = _mapper.Map<AuthorUpdateCommand>((id, request));
var result = await _mediator.Send(command);
if (result.IsError)
{
return BadRequest();
}
return Ok(result.Value);
}
After that, it returns this exception exactly as described in the Actual behavior
section.
Working code with constructors:
void Main()
{
var config = new MapperConfiguration(cfg =>
{
cfg.ShouldUseConstructor = p => p.IsPublic;
cfg.CreateMap<(Guid Id, AuthorRequest AuthorRequest), AuthorUpdateCommand>()
.ForCtorParam(nameof(AuthorUpdateCommand.Id), opt => opt.MapFrom(src => src.Id))
.IncludeMembers(src => src.AuthorRequest);
cfg.CreateMap<AuthorRequest, AuthorUpdateCommand>(MemberList.None);
});
config.AssertConfigurationIsValid();
//var expr = config.BuildExecutionPlan(typeof(IEnumerable<CollectionObject>), typeof(TestObject)).ToReadableString().Dump();
var mapper = config.CreateMapper();
try{
mapper.Map<AuthorUpdateCommand>((Guid.NewGuid(), new AuthorRequest("name", "bio", DateTime.Now))).Dump();
}catch(Exception ex) { ex.ToString().Dump(); }
}
public record AuthorRequest(string Name, string Biography, DateTime DateOfBirth);
public record AuthorUpdateCommand(Guid Id, string Name, string Biography, DateTime DateOfBirth) : AuthorCommand(Name, DateOfBirth);
public record AuthorCommand(string Name, DateTime DateOfBirth);