0

I want to get some understanding about how exactly Automapper is working. I know the basic idea, before I just used so called ViewModels to send the information that the business needs extracted from one or more database tables. Now I'm working on a legacy project where Automapper is used and maybe it offers more than just that but for the given moment I want to undestand (be able) to map my Domain object(s) to my DTO object(s) or vice-versa, I'm not sure which one is the correct way to go since I'm not able to do it.

This is a simple example of a console project I've made to test some basic functionalities of Automapper:

Visual Studio project

Where the DTO_User.cs class is meant to be used to send a data to the front end. It looks like this:

public class DTO_User
{
    public int ID { get; set; }
    public string Name { get; set; }
}

And the User.cs is the class which represent the actual domain data :

public class User
{
    public int ID { get; set; }
    public string Name { get; set; }
    public string PhoneNumber { get; set; }
}

So what I am trying to do. In my Program.cs I have a static method which creates some User obejcts:

public static List<Model.User> SeedUsers()
{
    List<Model.User> users = new List<Model.User>()
    {
        new Model.User { ID = 1, Name = "Ivan", PhoneNumber = "1235436"},
        new Model.User { ID = 2, Name = "Petkan", PhoneNumber = "00000000"},
        new Model.User { ID = 3, Name = "Dragan", PhoneNumber = "11111111"},
        new Model.User { ID = 4, Name = "Stoyan", PhoneNumber = "224545346"}
    };
    return users;
}

Then In my Main method I try to map this mocked data to my DTO List:

    static void Main(string[] args)
    {
        Mapper.CreateMap<DTO.DTO_User, Model.User>();

        //Mock user data as if it's taken from database

        List<Model.User> users = new List<Model.User>();
        users.AddRange(SeedUsers());//Simulate call to database

        //Create List of DTO Users
        List<DTO.DTO_User> dtoUsers = new List<DTO.DTO_User>();

        //Now map the database users to our DTO Users
        foreach (var user in users)
        {
            DTO.DTO_User u = Mapper.Map<Model.User, DTO.DTO_User>(user);
            dtoUsers.Add(u);
        }
    }

I got the error inside the foreah loop here:

DTO.DTO_User u = Mapper.Map<Model.User, DTO.DTO_User>(user);

Saying that I have some invalid arguments. Obviously I don't really catch the idea how Automapper was meant to implement the actual mapping. The code above is what was looking most natural to me. I know that this is pretty basic so an actual solution won't be too challenging but I would really appreciate if someone explains to me where my logic cracks and what is the idea behind the working code.

Leron
  • 9,546
  • 35
  • 156
  • 257
  • I tried, I got the same error but the example seems to simple to require too much additional set up. At least thi is what I think.. – Leron May 30 '15 at 18:23

1 Answers1

2

Trying adding an additional mapping:

Mapper.CreateMap<Model.User, DTO.DTO_User>();

and changing your Map invocation to the following:

DTO.DTO_User u = Mapper.Map<DTO.DTO_User>(user);
David Tansey
  • 5,813
  • 4
  • 35
  • 51
  • This set up works. However I've been following a very simple tutorial from `codeproject` and I really wonder why this works and mine - not. Could you provide some, even small, explanation on what is happening behind the scene so this works and the other not. Thanks anyway! – Leron May 30 '15 at 18:27
  • 1
    I'm pretty sure that you're mainly experiencing a problem because of the way your 'single' mapping was defined. When you say: `Mapper.CreateMap< T1, T2>();` you are asking for a mapping that can go from `T1` to `T2` but the opposite is NOT implied. You also need to define the converse: `Mapper.CreateMap< T2, T1>();` to go the other way. The syntax you used for the `Map` invocation is also valid and synonymous with what I posted. – David Tansey May 30 '15 at 18:33