0

Source/destination types

// 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>>;

Mapping configuration

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

Version: 13.0.1

Expected behavior

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.

Actual behavior

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)

Steps to reproduce

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.

1 Answer 1

0

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);
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.