skip to Main Content

To create PersonalChatDto

  1. I first create dto and map Chat class into it
  2. Map member options to existing dto
  3. Map partner(user I talk to) to existing dto
  4. And if partner is in contact book, i want mapper to take value of List<AvatarDto> Avatars and add avatar from contact to it.
var partner = chat.Members.Single(u => u.Id != user.Id);

        var contact = await contactRepository.GetContactAsync(user.Id, partner.Id);

        var member = await personalChatMemberRepository.GetMemberAsync(chat.Id, user.Id);

        var dto = mapper.Map<PersonalChatDto>(chat);
        mapper.Map(member, dto);
        mapper.Map(partner, dto);
        mapper.Map(contact, dto);

        return Result<PersonalChatDto>.Success(dto);

The problem is in mapping profile it shows me

var avatars = destMember ?? [];
var contactAvatar = src.CustomAvatar;

All props have correct values and even returns correct values.

  1. avatars value
  2. contactAvatar value
  3. return value

But after all mappings dto’s Avatars field is empty list

  1. dto object after all maps
  2. result

Here is mapping profile

CreateMap<Contact, PersonalChatDto>()
            .ForMember(dest => dest.Id,
                opt => opt.Ignore())
            .ForMember(dest => dest.FirstName, opt =>
                opt.MapFrom(src => src.CustomFirstName))
            .ForMember(dest => dest.LastName, opt =>
                opt.MapFrom(src => src.CustomLastName))
            .ForMember(dest => dest.Avatars, opt =>
                opt.MapFrom((src, _, destMember, context) =>
                {
                    var avatars = destMember ?? [];
                    var contactAvatar = src.CustomAvatar;

                    if (contactAvatar is null) return avatars;
                    
                    avatars.Add(context.Mapper.Map<AvatarDto>(contactAvatar));
                    
                    return avatars;
                }));

Contact class

public sealed class Contact : IEntity<Guid>
{
    public Guid OwnerId { get; set; }

    public User Owner { get; set; }

    public Guid UserId { get; set; }

    public User User { get; set; }

    public string CustomFirstName { get; set; }

    public string? CustomLastName { get; set; }

    public Guid CustomAvatarId { get; set; }

    public ContactAvatar? CustomAvatar { get; set; }

    public Guid Id { get; set; } = Guid.NewGuid();
}

PersonalChatDto record

public sealed record PersonalChatDto(
    [Required] Guid Id,
    [Required] string UserName,
    [Required] string FirstName,
    string? LastName,
    string? Biography,
    List<AvatarDto>? Avatars,
    [Required] bool IsMuted)
{
    public PersonalChatDto() 
        : this(default, default!, default!, null, null, null, default)
    {
    }
};

I was trying to configure map profile to add to list of existing items, instead of setting new value.

2

Answers


  1. Chosen as BEST ANSWER

    i just returned new result object with added User avatars and Contact avatar

    public sealed class ContactAvatarPersonalChatDtoResolver : IValueResolver<Contact, PersonalChatDto, List<AvatarDto>?>
    {
        public List<AvatarDto> Resolve(
            Contact source, PersonalChatDto destination, List<AvatarDto>? destMember, ResolutionContext context)
        {
            List<AvatarDto> result = [];
            
            if(destMember?.Count > 0)
                result.AddRange(destMember);
            if(source.CustomAvatar != null)
                result.Add(context.Mapper.Map<AvatarDto>(source.CustomAvatar) with
                {
                    AvatarPriority = AvatarPriority.Custom
                });
    
            return result;
        }
    }
    

  2. You should use ValueResolver by auto mapper

    CreateMap<Contact, PersonalChatDto>()
            .ForMember(dest => dest.Id,
                opt => opt.Ignore())
            .ForMember(dest => dest.FirstName, opt =>
                opt.MapFrom(src => src.CustomFirstName))
            .ForMember(dest => dest.LastName, opt =>
                opt.MapFrom(src => src.CustomLastName))
            .ForMember(dest => dest.Avatars, opt => opt.MapFrom<CustomResolver>());
    

    Resolver class will look like

    public class CustomResolver : IValueResolver<Source, Destination, int>
    {
        public int Resolve(Source source, Destination destination, int member, ResolutionContext context)
        {
            return source.Value1 + source.Value2;
        }
    }
    

    you should change the TDestmember as you need

    Also you should register this custome resolver as a service in the program.cs

    builder.Services.AddTransient<CustomResolver>();
    
    
           
    

    check https://docs.automapper.org/en/stable/Custom-value-resolvers.html#custom-value-resolvers

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search