'Inner properties became null when mapping using ProjectTo<> AutoMapper

I'm new to AutoMapper and its mapping mechanism, I have some models that need to process and query depending on its relationship. For example, I have Tag and Post with 1-to-N relationship.

Post.cs model

public class Post
{
    public Guid Id { get; set; }
    [Required]
    public string Title { get; set; }
    [Required]
    public string Content { get; set; }
    public DateTime Date { get; set; } = DateTime.UtcNow;
    public ICollection<TagPost> TagPosts { get; set; }
    public ICollection<Photo> Photos { get; set; }
    public ICollection<Comment> Comments { get; set; }
    public ICollection<PostFollowing> PostFollowers { get; set; }
}

Tag.cs model

public class Tag
{
    public Guid Id { get; set; }
    public string TagName { get; set; }
    public ICollection<TagPost> TagPosts { get; set; }
}

And the appropriate DTOs of both are

PostDto.cs

public class PostDto
{
    public Guid Id { get; set; }
    [Required]
    public string Title { get; set; }
    [Required]
    public string Content { get; set; }
    public string PosterName { get; set; }
    public bool IsFound { get; set; }
    public ICollection<PostParticipantDto> PostParticipants { get; set; }
    [Required]
    public TagDto Tag { get; set; }
    public ICollection<Photo> Photos { get; set; }
    public DateTime CreatedAt { get; set; }
}

Join table

public class TagPost
{
    public Guid PostId { get; set; }
    public Post Post { get; set; }
    public Guid Tag1Id { get; set; }
    public Tag1 Tag1 { get; set; }
}

TagDto.cs

public class TagDto
{
    public Guid Id { get; set; }
    public string TagName { get; set; }
    public ICollection<PostDto> Posts { get; set; }
}

As the relationship between Tag and Post is 1-To-N, so I want to retrieve all posts that have the same tag. I don't want to use .Include() and .ThenInclude() to get related data, instead I want to use .ProjectTo<> from AutoMapper. So I configured the Mapping profiles like

MappingProfiles.cs

public MappingProfiles()
{
        CreateMap<Post, PostDto>()
            .ForMember(dest => dest.PosterName,
                  o => o.MapFrom(src => src.PostFollowers.FirstOrDefault(x => x.isPoster).ApplicationUser.UserName))
            .ForMember(dest => dest.PostLocation, o => o.MapFrom(src => src.PostLocation))
            .ForMember(dest => dest.Tag, o => o.MapFrom(src => src.TagPosts.Select(tag => tag.Tag).FirstOrDefault()))
            .ForMember(dest => dest.Photos, o => o.MapFrom(src => src.Photos))
            .ForMember(dest => dest.PostParticipants, o => o.MapFrom(src => src.PostFollowers))
            .ForMember(dest => dest.CreatedAt, o => o.MapFrom(src => src.Date));
    
         CreateMap<Tag, TagDto>()
            .ForMember(dest => dest.Tag1Name, o => o.MapFrom(src => src.TagName));

         CreateMap<Tag, PostDto>()
            .ForMember(dest => dest.Tag, o => o.MapFrom(src => src.TagPosts.Select(tag => tag).FirstOrDefault()));
         
         CreateMap<TagPost, PostDto>()
            .ForMember(dest => dest.Tag, o => o.MapFrom(src => src.Tag));
}

And the method perform the query

public async Task<Result<TagDto>> Handle(Query request, CancellationToken cancellationToken)
{
        var result = await _context.Tags
            .Where(tag => tag.Id == request.TagId)
            .ProjectTo<TagDto>(_mapper.ConfigurationProvider
                , new { currentUsername = _userAccessor.GetUserName() }
                )
            .FirstOrDefaultAsync();
}

The mapping configuration seems correct, and the response data has all the mapped properties as I expected, however all of those properties became null. Here is the json response I receive when make a request.

{
    "id": "b7049a66-ea0d-4917-a52d-feb2b6dbe483",
    "tagName": "dog",
    "posts": [
        {
            "id": "00000000-0000-0000-0000-000000000000",
            "title": null,
            "content": null,
            "posterName": null,
            "isFound": false,
            "postParticipants": null,
            "tag": {
                "tagName": "dog"
            },
            "photos": null,
            "createdAt": "0001-01-01T00:00:00"
        },
        {
            "id": "00000000-0000-0000-0000-000000000000",
            "title": null,
            "content": null,
            "posterName": null,
            "postParticipants": null,
            "tag": {
                "tagName": "dog"
            },
            "photos": null,
            "createdAt": "0001-01-01T00:00:00"
        },
        {
            "id": "00000000-0000-0000-0000-000000000000",
            "title": null,
            "content": null,
            "posterName": null,
            "postParticipants": null,
            "tag1": {
                "tagName": "dog"
            },
            "photos": null,
            "createdAt": "0001-01-01T00:00:00"
        }
    ]
}



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source