Learn how YOU can convert your Objects between layers with Automapper, C#, .NET Core and VS Code
Tags: csharp, dotnet, tutorial, showdev
Published: 2020-01-22 23:48:46

---
title: Learn how YOU can convert your Objects between layers with Automapper, C#, .NET Core and VS Code
published: true
description: Mapping objects from one object to another is not only boring but time-consuming. Imagine using most of your time for business logic instead? That's why you need AutoMapper for .NET
tags: csharp, dotnet, tutorial, showdev
cover_image: https://thepracticaldev.s3.amazonaws.com/i/i3fvls3dore1w4kszrig.jpg
canonical_url: https://softchris.github.io/pages/dotnet-automapper.html
---

> When we read/write data we need to transport our information from one layer to the next. Our medium of transportation is usually by storing our data in a POCO a plain old C# object. However, how this object looks like it might differ between layers. In the top layer, we might have a view model. In a domain layer, the data might have been altered to represent what the object might look like in a domain. In our data layer, it might be changed yet again to be easily inserted into a data storage like a DB. The point is - changing this object as it passes through the layer is a cumbersome, boring and time-consuming process. Surely there must be a better way? There is, with a library called Auto mapper.

TLDR; this article will focus on teaching the use of the library AutoMapper. AutoMapper has a whole host of supporting libraries so we have chosen a specific approach, namely to use the version of AutoMapper that uses Dependency Injection. I should say that in the past I have not used AutoMapper with DI but straight up AutoMapper. This approach is meant to be used with ASP.NET Core where DI is a central part of your app. DI brings benefits of being able to test, as it is easy to mock out dependencies.

You can find a fully working repo here

> https://github.com/softchris/automapper-demo/tree/master

## References

- https://code-maze.com/automapper-net-core/
A quite good article that captures the important aspects of the library.

- [Official docs for AutoMapper](https://docs.automapper.org/en/stable/Getting-started.html)
Official documentation
- [GitHub repo for AutoMapper](https://github.com/AutoMapper/AutoMapper)
The official GitHub repo
- [Docs pages for .NET](https://docs.microsoft.com/en-us/dotnet/?wt.mc_id=devto-blog-chnoring)
If you are completely new to .NET, have a look here.
- [Getting started with .NET Core](https://docs.microsoft.com/en-us/dotnet/core/get-started?tabs=linux&wt.mc_id=devto-blog-chnoring)
Good intro to .NET Core.

## WHY

As we mentioned initially our data needs to move from layer to layer. Changing the data we pass should be an automated process. We don't really have any flow control logic, we just need to map one or several columns to a new set of columns. As our application grows we get more and more of these models. Automate this now before you spend way too much time on this versus actual business logic. :)

## WHAT

So what can AutoMapper do for us? 

1. **Map** from one type of object to another type
2. **Handle Complex differences**, sometimes we have cases that are more advanced than others. It might not be as simple as just a 1-1 replacement. We need to be able to handle 1-N changes too and AutoMapper can help us with that
3. **Default scenarios**, AutoMapper has some sensible defaults built-in which we can use to resolve certain 1-N cases

## DEMO

So what will we show? 

1. **Install and Set up**, let's look at how to get started by installing the needed libraries
2. **Configuration**, after install let's see how we instruct AutoMapper. Here we will show to use Profiles to tell AutoMapper what objects can be converted to what other objects. 
3. **Basic scenario**, let's look at a basic scenario in which we transform from one type
4. **Advanced scenarios**, Let's cover some more advanced scenarios including 1-N and defaults

### Install and Set up

Solution and project

```
dotnet new sln
dotnet new webapi -o api
dotnet sln add api/api.csproj
```

Install NuGet package

```
dotnet add api package AutoMapper.Extensions.Microsoft.DependencyInjection
```

### Configuration

First we need to add this line too `Startup.cs` and the method `ConfigureServices()`:

```csharp
services.AddAutoMapper(typeof(Startup));
```

Once you have that in place it's time to figure out how to map different classes to each other. For that, we will use a concept called `Profiles`. In the past, you would have one file where you entered all the mappings. While this works it might not make sense. 

> Wouldn't it be better if we could enter the mapping configuration closer to where it's used? 

Of course, it would. We call this way of organizing our code to organize by topic or domain. Let me show you an example:

```
/User
  UserController.cs
  UserModel.cs
  UserProfile.cs
  UserViewModel.cs
```

Whether you want to organize your code this way or not the concept `Profiles` means we created dedicated mapping classes for our mapping configuration. So let's take a look at how we can create one of those. First, let's think out a domain. We usually need the concept `User` as our app usually have users using it. So let's create the file `UserProfile.cs` and give it the following content:

```csharp
// UserProfile.cs

using AutoMapper;

namespace api.Profiles 
{
  public class UserProfile: Profile 
  {  
    public UserProfile()
    {
      CreateMap<User, UserViewModel>();
    }
  }
}
```

Above we are inheriting from the base class `Profile` and in the constructor, we set up our mapping:

```csharp
CreateMap<User, UserViewModel>();
```

> How shall we interpret the above though?

Well, it's 50/50 right? ;) Jokes aside. What we mean by the above is that given a `User` object, how do we create a `UserViewModel` object from it. This means we have set it up in one direction.

> What about the other direction?

I knew you'd ask that :) 

There are actually a few choices there depending on how each class looks, or rather how *compatible* they are.

Let's look at some different scenarios so you see how this affects the configuration.

## Basic scenario

In this basic scenario owe want to convert between a ViewModel and a Model in our service layer. We have a class `UserViewModel` and a class `UserModel`. Let's have a look at the code for each:

```csharp
// UserViewModel.cs

namespace api.Models 
{
  public class UserViewModel
  {
    public int Id { get; set; }
    public string FullName { get; set; }
  }
}
```

now the `UserModel`:

```csharp
namespace api.Models 
{
  public class UserModel
  {
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
  }
}
```

Looking at the above we can see that there are similarities `Id` but also differences `FullName` vs `FirstName` and `LastName`. We need to do the following:

- **Figure out** the difference between the two classes
- **Encode** the difference as a configuration in a profile class
- **Ensure** it works

### Figure out the difference

We deduce that a `FullName` is the same thing as `FirstName` + `LastName`. This might not always be so easy to figure but in this case it seemed quite simple.

### Encode the difference

At this point, we are ready to encode this in mapper configuration. So we create a file `UserProfile.cs` and give it the following content:

```csharp
using AutoMapper;

namespace api.Models 
{
  public class UserProfile: Profile 
  {  
    public UserProfile()
    {
      CreateMap<User, UserViewModel>();
    }
  }
}
```

What we are saying is, given a `User` we can create a `UserViewModel`.

> But wait, we are not done. The field names don't match. This won't work or?

Yes you are correct, we need to update our code above to use the helper method `ForMember()`, like so:

```csharp
CreateMap<User, UserViewModel>()
  .ForMember(dest => dest.FullName, opt => opt.MapFrom(src => src.FirstName + src.LastName));
```

Here we are saying, given the field `FullName`, construct it given `FirstName` + `LastName`. 

### Ensure it works

How do we know it works? Well, we have chosen to create a Web API project so let's create a route where we can test it out. 

Create the file `UserController.cs` and give it the following content:

```csharp
// UserController.cs

using AutoMapper;
using api.Models;

using Microsoft.AspNetCore.Mvc;

namespace api.Controllers 
{
  [ApiController]
  [Route("[controller]")]
  public class UserController 
  {
    private IMapper _mapper;
    public UserController(IMapper mapper)
    {
        _mapper = mapper;
    }

    
    [Route("/[controller]/[action]")]
    public string Get() 
    {
      var result = _mapper.Map<UserViewModel>(new User() { FirstName="Chris", LastName="Noring", Id = 1 });
      return result.FullName;
    }
  }
}
```

Above we have two things of interest.

1. **The constructor**, here we can see that we have injected an instance of `IMapper` called `mapper`. 

```csharp
private IMapper _mapper;
public DataController(IMapper mapper)
{
  _mapper = mapper;
}
```

2. **Controller action**, here we are setting up our route to listen to `controller/action` which means the name of the Controller class and the name of the method. Because our controller is called `UserController` that means the route is `<baseUrl/>user/get`.

```csharp
[Route("/[controller]/[action]")]
public string Get() 
{
  var result = _mapper.Map<UserViewModel>(new User() { FirstName="Chris", LastName="Noring", Id = 1 });
  return result.FullName;
}
```

Ok, let's try to run this with:

```
dotnet build
dotnet run
```

We should get the following:

![](https://thepracticaldev.s3.amazonaws.com/i/35a52xbx2o4l857hrk8n.png)

As you can see we are able to hit our route `https://localhost:5001/user/get` and it hits the correct class and method above. We can also see that our `_mapper` is able to resolve the `User` object we pass it and turn that into a ViewModel.

> It should be said though in a more realistic example we would probably fetch our `User` object using a service and then convert it into a ViewModel like the below code:

```csharp
var user = _userService.get();
var viewModel = _mapper.Map<UserViewModel>(user);
```

## Complex scenarios

Ok, we understand a basic scenario. What's a more complex scenario? Well, we might have nested classes where you have a class in a class like so:

```csharp
public class Order {
  public Customer Customer { get; set; }
  public DateTime Created { get; set; }
}
```

Above we have `Customer` being a part of `Order`. 

The target class might look like this:

```csharp
public class OrderViewModel {
  public string CustomerName { get; set; }
  public DateTime Created { get; set; }
}
```

The above actually works without any specific mapping rules?

> How is that possible?

Well, it depends on the shape `Customer`. `Customer` in this case just looks like this:

```csharp
public class Customer 
{
  public string Name { get; set }
}
```

AutoMapper is by default able to solve nesting like this as long as the name matches so `Customer -> Name` can be seen as `CustomerName`, quite powerful.

### Configure

You shouldn't take my word for it, so let me show you. We will need to do the following:

- **Configure our mapping**, we do this by creating a class `OrderProfile`
- **Create our model and view model**, we've already mentioned `Order` and `OrderViewModel`, we need to create those.
- **Add a router class**, we need to create the class `OrderController` 

**Configure our mapping**

Let's create our `OrderProfile` class. Start by creating the `OrderProfile.cs` and give it the following content:

```csharp
using AutoMapper;
using api.Models;

namespace api.Profiles {
  public class OrderProfile: Profile
  {
    private IMapper _mapper;
    public OrderProfile(IMapper mapper)
    {
      _mapper = mapper;
      CreateMap<Order, OrderViewModel>();
    }
  }
}
```

Above we are setting up a simple mapping:

```csharp
CreateMap<Order, OrderViewModel>();
```

**Create our model and view model**

Next let's create first our three model classes `Customer`, `Order` and `OrderViewModel`, like so:

```csharp
// Customer.cs

namespace api.Models
  {
  public class Customer
  {
      public string Name { get; set; }
  }
}
```

```csharp
// Order.cs

using System;

namespace api.Models
{
  public class Order
  {
    public Customer Customer { get; set; }
    public DateTime Created { get; set; }
  }
}
```

and lastly `OrderViewModel`:

```csharp
// OrderViewModel.cs

namespace api.Models
{
  public class OrderViewModel
  {
    public string CustomerName { get; set; }
  }
}
```

**Add a router class**

Create a file `OrderController.cs` with the following content:

```csharp
using AutoMapper;
using api.Models;
using System;

using Microsoft.AspNetCore.Mvc;

namespace api.Controllers
{
  [ApiController]
  [Route("[controller]")]
  public class OrderController
  {
    private IMapper _mapper;
    public OrderController(IMapper mapper)
    {
      _mapper = mapper;
    }

    [Route("/[controller]/[action]")]
    public string Get()
    {
      var orderViewModel = _mapper.Map<OrderViewModel>(new Order { 
        Customer = new Customer(){ Name = "Chris" }, 
        Created = DateTime.Now 
      });
      return orderViewModel.CustomerName;
    }
  }
}
```

Above we are constructing `orderViewModel` by passing it an `Order` instance. 

### Test it out

Running it, we get the following result:

![](https://thepracticaldev.s3.amazonaws.com/i/8e8r5uh5sij3bcpapamp.png)

As you can see above, this just works. It's able to take our `Order` class drill down into `Order->Customer->Name` and turn that into `CustomerName`. 

## Additional defaults

There are two additional defaults I wanted to show before wrapping up this article namely:

- **Reverse mapping**, normally when we set up mappings we need to specify mapping in both directions, from model to view model and from the view model to model. If we have a case like the above we can actually use a method `ReverseMap()` that automatically adds configuration for mapping in the other direction
- **Method resolver**, if we add methods to our class that name wise somewhat matches a field on the destination class then it will be invoked and will help us resolve our mapping

### Reverse Mapping

Given the code from our complex case let's use the `ReverseMap()` method on our `Order` configuration. Let's open the file `OrderProfile.cs` and change the code to the following:

```csharp
CreateMap<Order, OrderViewModel>()
  .ReverseMap();
```

Now open `OrderController.cs` and ensure the `Get()` method has the following code:

```csharp
var orderViewModel = _mapper.Map<OrderViewModel>(new Order { 
  Customer = new Customer(){ Name = "Chris" }, 
  Created = DateTime.Now 
});

var order = _mapper.Map<Order>(orderViewModel);
var name = order.Customer.Name;

return orderViewModel.CustomerName;
```

Above we have added the row:

```csharp
var order = _mapper.Map<Order>(orderViewModel);
var name = order.Customer.Name;
```

This converts our view model back to a model.

### Method resolver

This is not the only default that works out of the box. We can help with the conversion of one object to another by adding helper methods. to the source object. 

> That sounds a bit cryptic, can you elaborate?

Sure. Say you have a `User` class with fields `FirstName` and `LastName`. Let's also say we have `UserViewModel` with a `Fullname` field. How would we resolve that in a conversion? Your first go-to is probably to set up a config for this using the method `ForMember`. There is another way though, using a method. By adding the following method to the `User` class:

```csharp
public string GetFullname() {
  return string.Format("{0} {1}", this.FirstName, this.LastName);
}
```

We now have a way to *map* `FirstName` + `LastName` to a field `FullName`. Just think of the syntax is this way `Get<Fieldname>()`. 


**A second example**

This is powerful. Let's have a look at a new example. Imagine we have a `Location` class and a `LocationViewModel` class. `Location` looks like this:

```csharp
namespace api.Models 
{
  public class Location
  {
    public string Street { get; set; }      
    public string City { get; set; }
    public string Country  { get; set; }
  }
}
```

by adding a method `GetLocation()` looking like this:

```csharp
public string GetLocation() 
{
  return string.Format("{0} {1} {2}", Country, City, Street);
}
```

we don't actually have to define this mapping with the `MemberFor()` method. 

What's really useful is that we can use the same approach to convert a `LocationViewModel` to a `Location` object by adding similar methods to `LocationViewModel`. Change `LocationViewModel.cs` to the following:

```csharp
namespace api.Models
{
  public class LocationViewModel
  {
    public string Location { get; set; }

    public string GetCountry() 
    {
      return Location.Split(" ")[0];
    }

    public string GetCity()
    {
      return Location.Split(" ")[1];
    }

    public string GetStreet()
    {
      return Location.Split(" ")[2];
    }
  }
}
```

Just like with our `User`/ `UserViewModel` scenario we can now write code like this, to convert a `Location` to a `LocationViewModel` and back again:

```csharp
var locationViewmodel = _mapper.Map<LocationViewModel>(new Location() { 
  Street = "abc", 
  City= "Sthlm", 
  Country = "Sweden"  
});

var location = _mapper.Map<Location>(new LocationViewModel{   
  Location = "Country City Street" 
});
```

> NOTE, Because we added methods on the `LocationViewModel` class, that we expect to be used converting from it to `Location` object - we need to add the `ReverseMap()` call to our `LocationProfile` configuration. 

There is a more to learn about `AutoMapper` but hopefully, you've got a good idea of what to use it for and how it can help you and you can get started. Please check the reference section for more details.

## Summary

So what did we learn? We learned that AutoMapper is a great library to convert between different types of objects. Additionally, we learned that we can spread out the configuration in different `Profiles` to make our code easier to maintain. 
Lastly, we've learned that AutoMapper comes with a lot of smart defaults that means we barely need to config if we name our fields in a clever way or add a helper method.