I've created an API with ASPNET Core 2 that has a BlogPost service. The service handles creating blog posts and tags. The "Tags" are linked to the BlogPosts (as their children, by blogpostid), but i can't find a way to display those tags when i'm retrieving blogposts.
This is what i'm getting at the moment.
{
"id": 3,
"title": "Im Just Testing",
"body": "Esta Bien senor",
"type": "News",
"dateCreated": "9/20/2018 12:00:00 AM",
"author": "Dante",
"tags": []
}
This is my controller ->
[HttpGet("posts/{id}")]
public IActionResult GetBlogPostById(int id, bool includePostTags = true)
{
var blogPost = _blogPostService.GetBlogPostById(id, includePostTags);
if(blogPost == null)
{
return NotFound();
}
var blogPostDto = _mapper.Map<BlogPostDto>(blogPost);
return Ok(blogPostDto);
}
This is my BlogPostDTO
public class BlogPostDto
{
public int Id { get; set; }
public string Title { get; set; }
public string Body { get; set; }
public string Type { get; set; }
public string DateCreated { get; set; }
public string Author { get; set; }
public ICollection<BlogPostTagDto> Tags { get; set; }
= new List<BlogPostTagDto>();
}
And finally this is my BlogPostTag Entity ->
public class BlogPostTag
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required]
[MaxLength(50)]
public string TagName { get; set; }
[MaxLength(200)]
public string Description { get; set; }
[ForeignKey("BlogPostId")]
public BlogPost BlogPost { get; set; }
public int BlogPostId { get; set; }
}
And my BlogPostTagDto
public class BlogPostTagDto
{
public int Id { get; set; }
[Required(ErrorMessage = "You should provide a Tag Name value.")]
[MaxLength(50)]
public string TagName { get; set; }
[MaxLength(200)]
public string Description { get; set; }
}
TLDR: The BlogPostTags are created (i checked the DB), but i can't retrieve them in the "Get All Posts" call.
BlogPostService ->
public BlogPost GetBlogPostById(int id, bool includePostTags)
{
if(includePostTags)
{
return _context.BlogPosts.Include(c => c.BlogPostTags).Where(c => c.Id == id).FirstOrDefault();
}
return _context.BlogPosts.Where(c => c.Id == id).FirstOrDefault();
}
And DataContext (perhaps it helps) ->
public class DataContext : DbContext
{
public DataContext(DbContextOptions<DataContext> options) : base(options)
{
Database.Migrate();
}
public DbSet<User> Users { get; set; }
public DbSet<BlogPost> BlogPosts { get; set; }
public DbSet<BlogPostTag> BlogPostTags { get; set; }
}
BloGPost ENTITY
public class BlogPost
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required]
[MaxLength(100)]
public string Title { get; set; }
[Required]
[MaxLength(500)]
public string Body { get; set; }
public string Type { get; set; }
public string DateCreated { get; set; }
public string Author { get; set; }
public ICollection<BlogPostTag> BlogPostTags { get; set; }
= new List<BlogPostTag>();
}
Added Mapper profile ->
public AutoMapperProfile()
{
CreateMap<User, UserDto>();
CreateMap<UserDto, User>();
CreateMap<BlogPost, BlogPostDto>();
CreateMap<BlogPostDto, BlogPost>();
CreateMap<BlogPostTag, BlogPostTagForCreationDto>();
CreateMap<BlogPostTagForCreationDto, BlogPostTag>();
// CreateMap<BlogPostTagForCreationDto, BlogPostTag>();
}
SOLVED:
Apparently in my BlogPostDto i had to retrieve "BlogPostTagForCreationDto" instead of the normal Dto.
public ICollection<BlogPostTagForCreationDto> BlogPostTags { get; set; }
= new List<BlogPostTagForCreationDto>();
This PLUS changing the name from "Tags" to "BlogPostTags" seems to have fixed my issue. I've got to research more on why this happened.
After confirming in the comments that the problem is in the difference between the names BlogPostTags
and Tags
, it's evident that AutoMapper needs to be instructed to map from BlogPostTags
to Tags
when mapping from a BlogPost
to a BlogPostDto
. This can be configured inside of your AutoMapperProfile
, like this:
public AutoMapperProfile()
{
// ...
CreateMap<BlogPost, BlogPostDto>()
.ForMember(x => x.Tags, opt => opt.MapFrom(x => x.BlogPostTags));
}
All we're doing here is creating an explicit map from BlogPost
to BlogPostDto
, which allows us to take control of specific properties as they get mapped. In this case, we're simply stating that we want to MapFrom
BlogPostTags
to Tags
, accordingly.
It looks to me that you are missing a mapping:
CreateMap<BlogPostTag, BlogPostTagDto>();