Bobby R. Bobby R. - 1 month ago 19
C# Question

AutoMapper implementation (Post Static Api)

Having some trouble figuring this out. Seems like the original design was easy to follow but in the new design without the static Api there are so many ways to implement this. I am not finding any one way that is understandable. Plenty of start to finish videos and tutorials but with code syntax that I just don't know.

I just started making a new application and want to implement this from the start if possible.

Can someone give a detailed example of how to implement this from scratch with the following start point? i realize the example is so simple it doesn't need automapper

Using MVC w/ Code First & EF

Model Example

public class Person
{
public int id { get; set; }
public string name { get; set; }
public DateTime created { get;set;
}


ViewModel Example

public class User
{
public string name { get; set; }
}


Controller Example - (bit rough :) )

using AutoMapper;
......
[HttpPost]
public ActionResult AddUser(User user)
{

Person person = new Person();
person.name = user.name;
person.created = DateTime.Now;

db.Persons.Add(person);
db.SaveChanges();
return RedirectToAction("Index");
}


I just want to map the name field in this example from ViewModel to Model.

Some points that i'm particularly confused about in the examples I've found.

on this site > https://github.com/AutoMapper/AutoMapper/wiki/Getting-started


  • Where does this code go? Do i make one of these for every type to

    type mapping?

    Mapper.Initialize(cfg => cfg.CreateMap<Order, OrderDto>());


    Mapper.Initialize(cfg => cfg.CreateMap<User, Person>()); // this is what i did in the controller and Global.asax which isnt valid

  • Is this the part that goes in the Action result? Is
    "user" in my example above "order"?

    OrderDto dto = Mapper.Map<OrderDto>(order);

  • It also mentions "Where do I configure AutoMapper"

    In examples on the Internets it demosnstrates making a single reference in the Global.asax to a page I should create named "whateverIWant" which have Profiles? Im guessing that I put the initialization code (i mentioned above)in Global.asax in "Application_Start()"?



Is that it? is there a way to audit mapping of my types and where is this done? ie string manipulation. etc..

This Video > https://www.youtube.com/watch?v=-5sZ7hq3J10 loses me at 2:46, I haven't worked with repositories yet and not sure what they are. i think this is him auditing the mappings but its Greek to me.

Thank you to whoever clears my brain of all the mixed information i received trying to learn this from the plethora of code styles and version changes!




Update



The process I have so far...


  1. Add a class to my App_Start folder. I named it MappingConfig.cs

  2. Correct the namespace by removing ".App_Start" from the MappingConfig.cs code.

  3. Inside of the MappingConfig class create a method which will be used to initialize your maps.

    My method looks like this:

    public static void RegisterMaps()
    {
    AutoMapper.Mapper.Initialize(cfg => cfg.CreateMap<User, Person>());
    }



EDIT: Inside my method is the initalization. Is the initialization the thing that only needs to be done once? if so where do I map other types. I've seen "profile" in some code examples but no explanation on what it is. github site doesn't explain its use either.


  1. Inside of your controller-ActionResult you can map by doing this:

    var person = Mapper.Map<Person>(user);


    EDIT: This last line of code returns "Missing type map configuration or unsupported mapping."

  2. Now call the class and method in Global.asax inside of "Application_Start()" where the routes and bunde configs are to initialize the maps at the start of the program. I added it at the bottom like this:

    protected void Application_Start()
    {
    AreaRegistration.RegisterAllAreas();
    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
    RouteConfig.RegisterRoutes(RouteTable.Routes);
    BundleConfig.RegisterBundles(BundleTable.Bundles);
    MappingConfig.RegisterMaps(); // Right here
    }



I believe this is all I need to do to implement it? still working on intercepting the data that is being mapped so I can manipulate it and testing this to see if I am doing it right.

Answer

Looks like everything i did above is correct in terms of implementation except* to get it to work I had to map each of my initialization lines in both directions. This should be on the Github Getting-Started page... :/

Mapper.Initialize(cfg => cfg.CreateMap<Source, Dest>();
Mapper.Initialize(cfg => cfg.CreateMap<Dest, Source>();

or

Mapper.Initialize(cfg => cfg.CreateMap<Source, Dest>().ReverseMap();

Only then would it except my configuration without directly putting the code in every document I wanted to use it in (instead of global.asax) or declaring config as static.

It's funny that Nadeem Khoury mentioned this to me but I didn't try it because in this application and this item I do not need it to map in both directions in fact don't want it to. I ended up just being desperate to get it to work and read every automapper article on stack overflow up to and including this one Automapper exception: "Missing type map configuration or unsupported mapping." where Joseph Woodward says "You need to add the reverse mapping also". Need, being the keyword similar enough to required that I needed to even try it.

In short I believe Jimmy has a bug to work out. hopefully someone will report this bug for me. Or email Jimmy to suggest putting together a doc for each release that displays bare minimum requirements to implement this. I spent 3 days on this and I am out of time to learn anything else about AutoMapper for the application I'm building. Looks like its getting ManualMapper.