How to configure Auto mapper in class library project?
Asked Answered
C

6

43

I am using auto mapping first time.

I am working on c# application and I want to use auto mapper.

(I just want to know how to use it, so I don't have asp.net app neither MVC app.)

I have three class library projects.

enter image description here

I want to write transfer process in the service project.

So I want to know how and where should I configure the Auto Mapper ?

Clarkson answered 20/10, 2014 at 4:48 Comment(0)
S
29

You can place the configuration anywhere:

public class AutoMapperConfiguration
{
    public static void Configure()
    {
        Mapper.Initialize(x =>
            {
                x.AddProfile<MyMappings>();              
            });
    }
}

 public class MyMappings : Profile
{
    public override string ProfileName
    {
        get { return "MyMappings"; }
    }

    protected override void Configure()
    {
    ......
    }

But it has to be called by the application using the libraries at some point:

void Application_Start()
    {               
        AutoMapperConfiguration.Configure();
    }
Shown answered 20/10, 2014 at 12:5 Comment(0)
C
67

So based on Bruno's answer here and John Skeet's post about singletons I came up with the following solution to have this run only once and be completely isolated in class library unlike the accepted answer which relies on the consumer of the library to configure the mappings in the parent project:

public static class Mapping
{
    private static readonly Lazy<IMapper> Lazy = new Lazy<IMapper>(() =>
    {
        var config = new MapperConfiguration(cfg => {
            // This line ensures that internal properties are also mapped over.
            cfg.ShouldMapProperty = p => p.GetMethod.IsPublic || p.GetMethod.IsAssembly;
            cfg.AddProfile<MappingProfile>();
        });
        var mapper = config.CreateMapper();
        return mapper;
    });

    public static IMapper Mapper => Lazy.Value;
}

public class MappingProfile : Profile
{
    public MappingProfile()
    {
        CreateMap<Source, Destination>();
        // Additional mappings here...
    }
}

Then in your code where you need to map one object to another you can just do:

var destination = Mapping.Mapper.Map<Destination>(yourSourceInstance);

NOTE: This code is based on AutoMapper 6.2 and it might require some tweaking for older versions of AutoMapper.

Cochrane answered 23/3, 2018 at 19:6 Comment(4)
Thanks man. This is the best answer because it doesnt depend on anything but itself.Ander
This is a self-contained solution and can be used in any kind of app -- not just a class library. Thanks, @Marko.Loreenlorelei
where should I write this code? in parent project or class library project ?Selfpronouncing
@Selfpronouncing Class library project mate. That's entire point to isolate it in the class library and it just works wherever you reference that class library.Cochrane
S
29

You can place the configuration anywhere:

public class AutoMapperConfiguration
{
    public static void Configure()
    {
        Mapper.Initialize(x =>
            {
                x.AddProfile<MyMappings>();              
            });
    }
}

 public class MyMappings : Profile
{
    public override string ProfileName
    {
        get { return "MyMappings"; }
    }

    protected override void Configure()
    {
    ......
    }

But it has to be called by the application using the libraries at some point:

void Application_Start()
    {               
        AutoMapperConfiguration.Configure();
    }
Shown answered 20/10, 2014 at 12:5 Comment(0)
S
8

Nobody outside of your library has to configure AutoMapper

I recommend that you use the instance based approach using an IMapper. That way no one outside your library has to call any configuration method. You can define a MapperConfiguration and create the mapper from there all inside the class library.

var config = new MapperConfiguration(cfg => {
    cfg.AddProfile<AppProfile>();
    cfg.CreateMap<Source, Dest>();
});

IMapper mapper = config.CreateMapper();
// or
IMapper mapper = new Mapper(config);
var dest = mapper.Map<Source, Dest>(new Source());
Spenser answered 16/12, 2017 at 23:28 Comment(2)
Where can we place this code in a class library so that it automatically gets called (only once)?Fateful
@kamalpreet In a static constructor of a class maybe. Or take a look at Marko's answerSpenser
M
3

Marko's answer is correct.

We can also go by a below simple solution.

 public static class ObjectMapper
{
    public static IMapper Mapper
    {
        get
        {
            return AutoMapper.Mapper.Instance;
        }
    }
    static ObjectMapper()
    {
        CreateMap();
    }
    private static void CreateMap()
    {
        AutoMapper.Mapper.Initialize(cfg =>
        {
            cfg.CreateMap<SourceClass, DestinationClass>();
        });
    }
}
And we can use it like.
public class SourceClass
{
    public string Name { get; set; }
}
public class DestinationClass
{
    public string Name { get; set; }
}
SourceClass c1 = new SourceClass() { Name = "Mr.Ram" };

DestinationClass c2 = ObjectMapper.Mapper.Map<DestinationClass>(c1);
Marvellamarvellous answered 11/3, 2019 at 11:51 Comment(0)
G
0

I have used the Patel Vishal's solution and customized it to my needs. It's a generic class which makes sure only one instance of mapping is saved in memory per object mapping.

  1. TModel - is a DTO object
  2. TData - is a Database table object in Entity Framework
  3. DTO.IBaseModel - is a base class for DTO object which has one property: ID
  4. IBaseModel - is a base class for the entity framework database entity with ID property only

public static class ObjectMapper<TModel, TData>
    where TModel : class, DTO.IBaseModel, new() 
    where TData : class, IBaseModel, new()
{
    private static readonly MapperConfiguration _mapperConfiguration;
    public static IMapper Mapper => new Mapper(_mapperConfiguration);

    static ObjectMapper()
    {
        _mapperConfiguration ??= CreateMap();
    }

    private static MapperConfiguration CreateMap()
    {
        return new (cfg =>
        {
            cfg.CreateMap<TData, TModel>();
        });
    }
}

I am using this class in a BaseService<TData, TModel> (Service/Repository pattern) as such:

    public virtual TModel Convert(TData t)
    {
        return ObjectMapper<TModel, TData>.Mapper.Map<TModel>(t);
    }

As you can see, it's a virtual method. Mapping can be overwritten, if customization required by the inheriting Service.

Gayle answered 14/3, 2021 at 17:3 Comment(0)
O
0

I have come across this kind of requirement as well. What I have done in .Net 6.0 is, I create a library project and create the profile class:

public class AutoMapperProfile : Profile
{
    public AutoMapperProfile()
    {
        CreateMap<Entity, Dto>();
        CreateMap<Dto, Entity>();
        ......
    }
}

while in the api or web project, I just create a child class to inherit from the profile above, and register it in startup.cs services.AddAutoMapper(typeof(Startup));.

Overcurious answered 7/7, 2021 at 13:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.