What is AutoMapper and why should you use it?

AutoMapper is simply object to object mapping. Object-object mapping works by transforming an input object of one type into an output object of a different type. With AutoMapper you have much less code to write since mapping can occur in many places in an application. Object-object mapping leads to segregated models, where concerns for each layer can affect only types in that layer.

Now let’s show how we use AutoMapper on a simple test application. For purpose of this tutorial we will create small project for cars.

First we are going to create new folder and call it “AutoMapping” and with terminal run ‘dotnet new webapi’ inside the folder.
Then we are going to create new folder called ‘Models’ and make 2 models inside it, Make.cs and Models.cs because these are properties that every car has,like so:

For Makes:

using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace AutoMapping.Models
{
    public class Make
    {
        public Make()
        {
            Models = new Collection<Model>();
        }
        public int Id { get; set; }
        public string Name { get; set; }
        public ICollection<Model> Models { get; set; }

        
    }
}

For Models:

namespace AutoMapping.Models
{
    public class Model
    {
        public int Id { get; set; }
        public string Name { get; set; }

        public Make Make { get; set; }

        public int MakeId { get; set; }
    }
}

In you .csproj file add these packages and run dotnet restore.

 <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.3" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.0.1" />
    <PackageReference Include="AutoMapper" Version="6.2.2" />
    <PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="3.2.0" />
  </ItemGroup>
  <ItemGroup>
    <DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.1" />
    <DotNetCliToolReference Include="Microsoft.DotNet.Watcher.Tools" Version="2.0.0" />
    <DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.1" />
  </ItemGroup>

It is time to create our database. Add new folder and call it ‘Persistence and inside it create new c# class. The name of new class doesn’t have to be like we are going to name it but it is a rule of thumb to name it ‘{project name}DbContext.cs’ so our name is going to be ‘AutoMappingDbContext.cs’. Inside we derive our class from DbContext and in constructor we put generic class and call it ‘options’ and finally pass it to our base class.

using Microsoft.EntityFrameworkCore;

namespace AutoMapping.Persistence
{
    public class AutoMappingDbContext : DbContext
    {
         public AutoMappingDbContext(DbContextOptions<AutoMappingDbContext> options) 
          : base(options)
        {
        }
    }
}

Now we need to register this DbContext as a service for our dependency injection. In StartUp.cs inside ConfigureServices method add this before mvc:

services.AddDbContext<AutoMappingDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("Default")));

Don’t forget to include these at the top:
using AutoMapping.Persistence;
using Microsoft.EntityFrameworkCore;

In appsettings.json we add connection string:

It’s time to create our database using migrations like in our other tutorials. In our dbcontext we need to add dbset like so:

Run this command to create first migration: dotnet ef migrations add Initial. Now check the migration and make sure it’s not empty. Run dotnet ef database update.For some reason Entity Framework does not recognize that our Models table should be plural but we will fix that in a moment. Now in your SQL server you will see new database with name AutoMapping. Now we need to go to our Model class and add this:

Now add another migration with and call it however you want, we will call it ‘ChangesOnModelClass’. With this we are changing the name of a table though migration, remember, you should never change it manually when you are doing code first and buliding your Database context using migrations.

For us to continue we will need some data in our newly created database so lets make another empty migration call it ‘SeedDatabase’ and manually insert the following code.

In the Up method:

            migrationBuilder.Sql("INSERT INTO Makes (Name) VALUES ('Make1')");
            migrationBuilder.Sql("INSERT INTO Makes (Name) VALUES ('Make2')");
            migrationBuilder.Sql("INSERT INTO Makes (Name) VALUES ('Make3')");

            migrationBuilder.Sql("INSERT INTO Models (Name, MakeID) VALUES ('Make1-ModelA', (SELECT ID FROM Makes WHERE Name = 'Make1'))");
            migrationBuilder.Sql("INSERT INTO Models (Name, MakeID) VALUES ('Make1-ModelB', (SELECT ID FROM Makes WHERE Name = 'Make1'))");
            migrationBuilder.Sql("INSERT INTO Models (Name, MakeID) VALUES ('Make1-ModelC', (SELECT ID FROM Makes WHERE Name = 'Make1'))");

            migrationBuilder.Sql("INSERT INTO Models (Name, MakeID) VALUES ('Make2-ModelA', (SELECT ID FROM Makes WHERE Name = 'Make2'))");
            migrationBuilder.Sql("INSERT INTO Models (Name, MakeID) VALUES ('Make2-ModelB', (SELECT ID FROM Makes WHERE Name = 'Make2'))");
            migrationBuilder.Sql("INSERT INTO Models (Name, MakeID) VALUES ('Make2-ModelC', (SELECT ID FROM Makes WHERE Name = 'Make2'))");

            migrationBuilder.Sql("INSERT INTO Models (Name, MakeID) VALUES ('Make3-ModelA', (SELECT ID FROM Makes WHERE Name = 'Make3'))");
            migrationBuilder.Sql("INSERT INTO Models (Name, MakeID) VALUES ('Make3-ModelB', (SELECT ID FROM Makes WHERE Name = 'Make3'))");
            migrationBuilder.Sql("INSERT INTO Models (Name, MakeID) VALUES ('Make3-ModelC', (SELECT ID FROM Makes WHERE Name = 'Make3'))");

In Down method:

migrationBuilder.Sql("DELETE FROM Makes WHERE Name IN ('Make1', 'Make2', 'Make3')");

Before we can create mapping profile and explain how we use mapping we have to create API. Create new folder inside our project and call it ‘Resources’. Make 2 classes, ModelResource and MakeResource. We use these resource to receive data from front-end and also to send data.

Implementing AutoMapper

In StartUp.cs at ConfigureServices method we need to add services.AddAutoMapper();. Now we can go to our Makes controller and inject IMapper in constructor and it should look like this:

using System.Collections.Generic;
using System.Threading.Tasks;
using AutoMapper;
using AutoMapping.Controllers.Resources;
using AutoMapping.Models;
using AutoMapping.Persistence;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;

namespace AutoMapping.Controllers
{
    public class MakesController : Controller
    {
        private readonly AutoMappingDbContext context;
        private readonly IMapper mapper;
        public MakesController(AutoMappingDbContext context, IMapper mapper)
        {
            this.mapper = mapper;
            this.context = context;
        }
        [HttpGet("/api/makes")]
        public async Task<IEnumerable<MakeResource>> GetMakes()
        {
            var makes = await context.Makes.Include(m => m.Models).ToListAsync();

            return mapper.Map<List<Make>, List<MakeResource>>(makes);     // .Map is generic method with 2 parameters, source and target type, here our source type is List of Make and target type is List of MakeResource.

           
        }
    }
}

The only thing left to do is to make a Mapping Profile so our Mapper knows how to map properties from one class to the other.
Create new folder inside our application and call it ‘Mapping’. Inside Mapping folder create new class and call it ‘MappingProfile.cs’, paste the following code:

using AutoMapper;
using AutoMapping.Controllers.Resources;
using AutoMapping.Models;

namespace AutoMapping.Mapping
{
    public class MappingProfile : Profile
    {
        public MappingProfile()
        {
            CreateMap<Make,MakeResource>();
            CreateMap<Model,ModelResource>();
        }
    }
}

And now, when you run the project and go to localhost:5000/api/makes you should get all the date from the database.
This kind of mapping is when you are sending data from back-end to front-end, but if you need to do it another way around you need to add new Map in mapping profile.