21

I have to classes Like

class A
{
 public int id {get; set;}
}

class B
{
 public C c {get; set;}
}

class C
{
 public int id {get; set;}
 public string Name {get; set;}
}

My requirement is to map id of class A to id of class C. Now what I was doing till now was: Mapper.CreateMap().ForMember(des => des.C.Id, src => src.MapFrom(x => x.id));

and it was working fine.

Now seems like Auto mapper has changed their implementation. and I am getting warning as below:

AutoMapper.Mapper.CreateMap()' is obsolete: 'Dynamically creating maps will be removed in version 5.0. Use a MapperConfiguration instance and store statically as needed, or Mapper.Initialize. Use CreateMapper to create a mapper instance.

I need to map some properties of classes which has different name and structure. Any help on this.

Sharad
  • 435
  • 1
  • 5
  • 18
  • 2
    Have a look at [this](http://stackoverflow.com/questions/35256008/automapper-migrating-from-static-api) post. – diiN__________ Apr 04 '16 at 09:05
  • 1
    @diiN_'s comment should point you in the right direction, however if you're still struggling you could install a previous version using NuGet or using the command prompt: Install-Package AutoMapper -Version 4.1.0 –  Apr 04 '16 at 11:39

3 Answers3

33

Previously

  Mapper.CreateMap<Src, Dest>()
 .ForMember(d => d.UserName, opt => opt.MapFrom(/* ????? */));

The problem here is mapping definitions are static, defined once and reused throughout the lifetime of the application. Before 3.3, you would need to re-define the mapping on every request, with the hard-coded value. And since the mapping configuration is created in a separate location than our mapping execution, we need some way to introduce a runtime parameter in our configuration, then supply it during execution.

This is accomplished in two parts: the mapping definition where we create a runtime parameter, then at execution time when we supply it. To create the mapping definition with a runtime parameter, we “fake” a closure that includes a named local variable:

Mapper.Initialize(cfg => {

string userName = null;
cfg.CreateMap<Source, Dest>()
    .ForMember(d => d.UserName, 
        opt => opt.MapFrom(src => userName)
    );
});

For more information see this

For one or more classes

 cfg.CreateMissingTypeMaps = true;
 cfg.CreateMap<Source, Dest>()
    .ForMember(d => d.UserName, 
        opt => opt.MapFrom(src => userName)
    );

 cfg.CreateMap<AbcEditViewModel, Abc>();
 cfg.CreateMap<Abc, AbcEditViewModel>();
});

In mapping class

  IMapper mapper = config.CreateMapper();
  var source = new AbcEditViewModel();
  var dest = mapper.Map<AbcEditViewModel, Abct>(source);
Anik Saha
  • 4,313
  • 2
  • 26
  • 41
  • it is working fine BUT THERE IS A PROBLEM AFTER IT. In case we have exactly same properties in two classes than only Mapper.map(Source, Destination) works and no need for explicitly mapping. But once we used Mapper.Initialize(cfg => { string userName = null; cfg.CreateMap() .ForMember(d => d.UserName, opt => opt.MapFrom(src => userName) ); }); No other Mapper.map(Source, Destination) works ( for which source and destination have same properties and structure) – Sharad Apr 04 '16 at 10:17
  • Is you source and destination class is generic? You have to create map for every mapping combination – Anik Saha Apr 04 '16 at 10:41
  • Do you show me what have done. Show the code. Where do you create map and where are you mapping? Also I improved my answer. Do you implement this way ? – Anik Saha Apr 04 '16 at 11:24
  • problem I am facing is once I implement for two mapper class for which I have different properties and structure and use the way you suggested than it work fine for this case. I added this code in a .cs file in app_start folder. and register it to the GlobalConfiguration.Configure() inside global.asax --> application start method. But if later in the code if I need to Map two classes having similar properties and structure than that part does't work. which was working till now by using just Mapper.Map(source, destination) line. – Sharad Apr 04 '16 at 11:27
  • What is the problem of adding code to the question with full description? – Anik Saha Apr 04 '16 at 11:28
5

Another way that seems a bit cleaner is to make a MappingProfile class which inherits from the Profile class of AutoMapper

public class MappingProfile:Profile
{
    public MappingProfile()
    {
        CreateMap<Source1, Destination1>();
        CreateMap<Source2, Destination2>();
        ...
    }
}

Then you initialize the mapping with Mapper.Initialize(c => c.AddProfile<MappingProfile>()); in your startup code

That will allow you to use the mapping anywhere by calling

destination1Collection = source1Collection.Select(Mapper.Map<Source1, Destination1>);
Leonard Lay
  • 89
  • 1
  • 5
0

Finally I found the resolution. I was doing: Mapper.Initialize{ Mapping field from source to destination } in the App_start and adding this file to the global.asax--> Application_Start() --> GlobalConfiguration.

I need to add one more line inside my Mapper.Initialize which is cfg.CreateMissingTypeMaps = true;

Now this code will work for explicit mapping where two classes don't have the same structure and names of properties.

Apart from this, if we need to map properties of two class with the same structure the code Mapper.map(source, destination) will also work, which was not working earlier.

Let me know if someone is having difficulty with the solution. Thanks all for the above reply.

STLDev
  • 5,950
  • 25
  • 36
Sharad
  • 435
  • 1
  • 5
  • 18