How to setup Automapper in ASP.NET Core

by theutz   Last Updated June 09, 2019 22:26 PM

I'm relatively new at .NET, and I decided to tackle .NET Core instead of learning the "old ways". I found a detailed article about setting up AutoMapper for .NET Core here, but is there a more simple walkthrough for a newbie?



Answers 11


I figured it out! Here's the details:

  1. Add the main AutoMapper Package to your solution via NuGet.
  2. Add the AutoMapper Dependency Injection Package to your solution via NuGet.

  3. Create a new class for a mapping profile. (I made a class in the main solution directory called MappingProfile.cs and add the following code.) I'll use a User and UserDto object as an example.

    public class MappingProfile : Profile {
        public MappingProfile() {
            // Add as many of these lines as you need to map your objects
            CreateMap<User, UserDto>();
            CreateMap<UserDto, User>();
        }
    }
    
  4. Then add the AutoMapperConfiguration in the Startup.cs as shown below:

    public void ConfigureServices(IServiceCollection services) {
        // .... Ignore code before this
    
       // Auto Mapper Configurations
        var mappingConfig = new MapperConfiguration(mc =>
        {
            mc.AddProfile(new MappingProfile());
        });
    
        IMapper mapper = mappingConfig.CreateMapper();
        services.AddSingleton(mapper);
    
        services.AddMvc();
    
    }
    
  5. To invoke the mapped object in code, do something like the following:

    public class UserController : Controller {
    
        // Create a field to store the mapper object
        private readonly IMapper _mapper;
    
        // Assign the object in the constructor for dependency injection
        public UserController(IMapper mapper) {
            _mapper = mapper;
        }
    
        public async Task<IActionResult> Edit(string id) {
    
            // Instantiate source object
            // (Get it from the database or whatever your code calls for)
            var user = await _context.Users
                .SingleOrDefaultAsync(u => u.Id == id);
    
            // Instantiate the mapped data transfer object
            // using the mapper you stored in the private field.
            // The type of the source object is the first type argument
            // and the type of the destination is the second.
            // Pass the source object you just instantiated above
            // as the argument to the _mapper.Map<>() method.
            var model = _mapper.Map<UserDto>(user);
    
            // .... Do whatever you want after that!
        }
    }
    

I hope this helps someone starting fresh with ASP.NET Core! I welcome any feedback or criticisms as I'm still new to the .NET world!

theutz
theutz
October 27, 2016 02:34 AM

theutz' answer here is very good, I just want to add this:

If you let your mapping profile inherit from MapperConfigurationExpression instead of Profile, you can very simply add a test to verify your mapping setup, which is always handy:

[Fact]
public void MappingProfile_VerifyMappings()
{
    var mappingProfile = new MappingProfile();

    var config = new MapperConfiguration(mappingProfile);
    var mapper = new Mapper(config);

    (mapper as IMapper).ConfigurationProvider.AssertConfigurationIsValid();
}
Arve Systad
Arve Systad
March 30, 2017 12:39 PM

about theutz answer , there is no need to specify the IMapper mapper parrameter at the controllers constructor.

you can use the Mapper as it is a static member at any place of the code.

public class UserController : Controller {
   public someMethod()
   {
      Mapper.Map<User, UserDto>(user);
   }
}
yaronmil
yaronmil
May 10, 2017 05:38 AM

I am using AutoMapper 6.1.1 and asp.net Core 1.1.2.

First of all, define Profile classes inherited by Profile Class of Automapper. I Created IProfile interface which is empty, the purpose is only to find the classes of this type.

 public class UserProfile : Profile, IProfile
    {
        public UserProfile()
        {
            CreateMap<User, UserModel>();
            CreateMap<UserModel, User>();
        }
    }

Now create a separate class e.g Mappings

 public class Mappings
    {
     public static void RegisterMappings()
     {            
       var all =
       Assembly
          .GetEntryAssembly()
          .GetReferencedAssemblies()
          .Select(Assembly.Load)
          .SelectMany(x => x.DefinedTypes)
          .Where(type => typeof(IProfile).GetTypeInfo().IsAssignableFrom(type.AsType()));

            foreach (var ti in all)
            {
                var t = ti.AsType();
                if (t.Equals(typeof(IProfile)))
                {
                    Mapper.Initialize(cfg =>
                    {
                        cfg.AddProfiles(t); // Initialise each Profile classe
                    });
                }
            }         
        }

    }

Now in MVC Core web Project in Startup.cs file, in the constructor, call Mapping class which will initialize all mappings at the time of application loading.

Mappings.RegisterMappings();
Aamir
Aamir
July 25, 2017 01:19 AM

To add onto what Arve Systad mentioned for testing. If for whatever reason you're like me and want to maintain the inheritance structure provided in theutz solution, you can set up the MapperConfiguration like so:

var mappingProfile = new MappingProfile();
var config = new MapperConfiguration(cfg =>
{
    cfg.AddProfile(mappingProfile);
});
var mapper = new Mapper(config);

I did this in NUnit.

LandSharks
LandSharks
March 09, 2018 20:18 PM

services.AddAutoMapper(); didn't work for me. (I am using Asp.Net Core 2.0)

After configuring as below

   var config = new AutoMapper.MapperConfiguration(cfg =>
   {                 
       cfg.CreateMap<ClientCustomer, Models.Customer>();
   });

initialize the mapper IMapper mapper = config.CreateMapper();

and add the mapper object to services as a singleton services.AddSingleton(mapper);

this way I am able to add a DI to controller

  private IMapper autoMapper = null;

  public VerifyController(IMapper mapper)
  {              
   autoMapper = mapper;  
  }

and I have used as below in my action methods

  ClientCustomer customerObj = autoMapper.Map<ClientCustomer>(customer);
Venkat pv
Venkat pv
March 24, 2018 15:27 PM

I want to extend @theutz's answers - namely this line :

// services.AddAutoMapper(typeof(Startup));  // <-- newer automapper version uses this signature.

There is a bug (probably) in AutoMapper.Extensions.Microsoft.DependencyInjection version 3.2.0. (I'm using .NET Core 2.0)

This is tackled in this GitHub issue. If your classes inheriting AutoMapper's Profile class exist outside of assembly where you Startup class is they will probably not be registered if your AutoMapper injection looks like this:

services.AddAutoMapper();

unless you explicitly specify which assemblies to search AutoMapper profiles for.

It can be done like this in your Startup.ConfigureServices:

services.AddAutoMapper(<assembies> or <type_in_assemblies>);

where "assemblies" and "type_in_assemblies" point to the assembly where Profile classes in your application are specified. E.g:

services.AddAutoMapper(typeof(ProfileInOtherAssembly), typeof(ProfileInYetAnotherAssembly));

I suppose (and I put emphasis on this word) that due to following implementaion of parameterless overaload (source code from GitHub) :

public static IServiceCollection AddAutoMapper(this IServiceCollection services)
{
     return services.AddAutoMapper(null, AppDomain.CurrentDomain.GetAssemblies());
}

we rely on CLR having already JITed assembly containing AutoMapper profiles which might be or might not be true as they are only jitted when needed (more deatils in this StackOverflow question).

GrayCat
GrayCat
May 04, 2018 15:30 PM

Step To Use AutoMapper with ASP.NET Core.

Step 1. Installing AutoMapper.Extensions.Microsoft.DependencyInjection from NuGet Package.

enter image description here

Step 2. Create a Folder in Solution to keep Mappings with Name "Mappings".

enter image description here

Step 3. After adding Mapping folder we have added a class with Name "MappingProfile" this name can anything unique and good to understand.

In this class, we are going to Maintain all Mappings.

enter image description here

Step 4. Initializing Mapper in Startup "ConfigureServices"

In Startup Class, we Need to Initialize Profile which we have created and also Register AutoMapper Service.

  Mapper.Initialize(cfg => cfg.AddProfile<MappingProfile>());

  services.AddAutoMapper();

Code Snippet to show ConfigureServices Method where we need to Initialize and Register AutoMapper.

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }


    public void ConfigureServices(IServiceCollection services)
    {
        services.Configure<CookiePolicyOptions>(options =>
        {
            // This lambda determines whether user consent for non-essential cookies is needed for a given request.
            options.CheckConsentNeeded = context => true;
            options.MinimumSameSitePolicy = SameSiteMode.None;
        });


        // Start Registering and Initializing AutoMapper

        Mapper.Initialize(cfg => cfg.AddProfile<MappingProfile>());
        services.AddAutoMapper();

        // End Registering and Initializing AutoMapper

        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

    }}

Step 5. Get Output.

To Get Mapped result we need to call AutoMapper.Mapper.Map and pass Proper Destination and Source.

AutoMapper.Mapper.Map<Destination>(source);

CodeSnippet

    [HttpPost]
    public void Post([FromBody] SchemeMasterViewModel schemeMaster)
    {
        if (ModelState.IsValid)
        {
            var mappedresult = AutoMapper.Mapper.Map<SchemeMaster>(schemeMaster);
        }
    }
Saineshwar
Saineshwar
November 24, 2018 06:18 AM

For ASP.NET Core, the following is direct from Automapper and is 1 line in your startup class: https://github.com/AutoMapper/AutoMapper.Extensions.Microsoft.DependencyInjection/blob/master/README.md

Simply add some profile classes. Then add below to your startup.cs class. services.AddAutoMapper(OneOfYourProfileClassNamesHereSoItCanFindYourProfileAssembly)

Then simply Inject IMapper in your controllers or wherever you need it:

public class EmployeesController {

    private readonly IMapper _mapper;

    public EmployeesController(IMapper mapper){

        _mapper = mapper;
    }

And if you want to use ProjectTo its now simply:

var customers = await dbContext.Customers.ProjectTo<CustomerDto>(_mapper.ConfigurationProvider).ToListAsync()
dalcam
dalcam
February 19, 2019 06:26 AM

I've found automapper hard to get started with. When I couldn't get it injected in my Test class's constructor I've dropped it entirely. Instead I'll be using ModelBindings for properties that are non-editable and Data Transfer Classes for properties that should be hidden and handle the mapping myself.

Metonymy
Metonymy
May 08, 2019 15:07 PM

In my Startup.cs

services.AddAutoMapper(new Type[] { typeof(DAL.MapperProfile) });            

In my data access project

namespace DAL
{
    public class MapperProfile : Profile
    {
        // place holder for AddAutoMapper (to bring in the DAL assembly)
    }
}

In my model definition

namespace DAL.Models
{
    public class PositionProfile : Profile
    {
        public PositionProfile()
        {
            CreateMap<Position, PositionDto_v1>();
        }
    }

    public class Position
    {
        ...
    }
Brian Rice
Brian Rice
June 09, 2019 22:25 PM

Related Questions





Getting related data via an AutoMapper mapping?

Updated March 31, 2018 12:26 PM