Я относительно новичок в .NET и решил заняться .NET Core вместо того, чтобы изучать «старые способы». Я нашел подробную статью о настройке AutoMapper для .NET Core здесь, но есть ли более простое руководство для новичков?

theutz

Ответов: 17

Ответы (17)

I figured it out! Here's the details:

  1. Добавьте основной пакет AutoMapper в свое решение через NuGet.

  2. Добавьте пакет внедрения зависимостей AutoMapper в свое решение через NuGet.

  3. Создайте новый класс для профиля сопоставления. (Я создал класс в основном каталоге решения под названием MappingProfile.cs и добавил следующий код.) Я буду использовать объекты User и UserDto в качестве пример.

     открытый класс MappingProfile: Profile {
         public MappingProfile () {
             // Добавьте столько линий, сколько вам нужно для отображения ваших объектов
             CreateMap <Пользователь, UserDto> ();
             CreateMap  ();
         }
     }
    
  4. Затем добавьте AutoMapperConfiguration в Startup.cs, как показано ниже:

     public void ConfigureServices (IServiceCollection services) {
         // .... Игнорировать код перед этим
    
        // Конфигурации Auto Mapper
         var mapperConfig = new MapperConfiguration (mc =>
         {
             mc.AddProfile (новый MappingProfile ());
         });
    
         IMapper mapper = mapperConfig.CreateMapper ();
         services.AddSingleton (картограф);
    
         services.AddMvc ();
    
     }
    
  5. Чтобы вызвать сопоставленный объект в коде, сделайте что-нибудь вроде следующего:

     открытый класс UserController: Controller {
    
         // Создаем поле для хранения объекта сопоставления
         частный только для чтения IMapper _mapper;
    
         // Назначаем объект в конструкторе для внедрения зависимости
         public UserController (IMapper mapper) {
             _mapper = картограф;
         }
    
         общедоступная асинхронная задача  Edit (string id) {
    
             // Создание экземпляра исходного объекта
             // (Получить его из базы данных или из того, что требует код)
             var user = await _context.Users
                 .SingleOrDefaultAsync (u => u.Id == id);
    
             // Создание отображаемого объекта передачи данных
             // используя преобразователь, который вы сохранили в частном поле.
             // Тип исходного объекта - это первый аргумент типа
             // а тип назначения - второй.
             // Передаем исходный объект, который вы только что создали выше
             // в качестве аргумента метода _mapper.Map <> ().
             var model = _mapper.Map  (пользователь);
    
             // .... После этого делайте что хотите!
         }
     }
    

Я хочу продолжить ответы @ theutz, а именно эту строку:

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

Есть ошибка (вероятно) в AutoMapper.Extensions.Microsoft.DependencyInjection версии 3.2.0. (Я использую .NET Core 2.0)

Эта проблема решена в this GitHub. Если ваши классы, наследующие класс AutoMapper Profile, существуют за пределами сборки, в которой вы используете класс Startup, они, вероятно, не будут зарегистрированы, если ваша инъекция AutoMapper выглядит следующим образом:

services.AddAutoMapper();

, если вы явно не укажете, какие сборки следует искать в профилях AutoMapper.

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

services.AddAutoMapper( or );

где «сборки» и «type_in_assemblies» указывают на сборку, в которой указаны классы профиля в вашем приложении. Например:

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

Я предполагаю (и я подчеркиваю это слово), что из-за следующей реализации перегрузки без параметров (исходный код из GitHub):

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

мы полагаемся на CLR, уже имеющую JIT-сборку, содержащую профили AutoMapper, которые могут быть или не соответствовать действительности, поскольку они изменяются только при необходимости (подробнее см. этот вопрос StackOverflow).

Шаг для использования AutoMapper с ASP.NET Core.

Шаг 1. Установка AutoMapper.Extensions.Microsoft.DependencyInjection из пакета NuGet.

enter image description here

Шаг 2. Создайте папку в решении для хранения сопоставлений с именем «Сопоставления».

enter image description here

Шаг 3. После добавления папки Mapping мы добавили класс с именем «MappingProfile», это имя может быть уникальным и понятным.

В этом классе мы собираемся сохранить все сопоставления.

enter image description here

Шаг 4. Инициализация Mapper в Startup «ConfigureServices»

В классе запуска нам нужно инициализировать профиль, который мы создали, а также зарегистрировать службу AutoMapper.

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

  services.AddAutoMapper();

Фрагмент кода для отображения метода ConfigureServices, в котором нам нужно инициализировать и зарегистрировать AutoMapper.

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

    public IConfiguration Configuration { get; }


    public void ConfigureServices(IServiceCollection services)
    {
        services.Configure(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());
        services.AddAutoMapper();

        // End Registering and Initializing AutoMapper

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

    }}

Шаг 5. Получить результат.

Чтобы получить результат сопоставления, нам нужно вызвать AutoMapper.Mapper.Map и передать правильное назначение и источник.

AutoMapper.Mapper.Map(source);

CodeSnippet

    [HttpPost]
    public void Post([FromBody] SchemeMasterViewModel schemeMaster)
    {
        if (ModelState.IsValid)
        {
            var mappedresult = AutoMapper.Mapper.Map(schemeMaster);
        }
    }

Для ASP.NET Core (протестировано с использованием 2.0+ и 3.0), если вы предпочитаете читать исходную документацию: https://github.com/AutoMapper/AutoMapper.Extensions.Microsoft.DependencyInjection/blob/master/README.md

В противном случае следующие 4 шага работают:

  1. Установите AutoMapper.Extensions.Microsoft.DependancyInjection из nuget.

  2. Просто добавьте несколько классов профиля.

  3. Затем добавьте ниже в свой класс startup.cs. services.AddAutoMapper (OneOfYourProfileClassNamesHere)

  4. Затем просто введите IMapper в свои контроллеры или где угодно:

public class EmployeesController {

    private readonly IMapper _mapper;

    public EmployeesController(IMapper mapper){

        _mapper = mapper;
    }

И если вы хотите использовать ProjectTo, это просто:

var customers = await dbContext.Customers.ProjectTo(_mapper.ConfigurationProvider).ToListAsync()

Я решил это таким образом (аналогично описанному выше, но мне кажется, что это более чистое решение). Работает с .NET Core 3.x

Создайте класс MappingProfile.cs и заполните конструктор картами (я планирую использовать один класс для хранения всех моих сопоставлений)

    public class MappingProfile : Profile
    {
        public MappingProfile()
        {
            CreateMap().ReverseMap();
        }
    }

В Startup.cs добавьте ниже, чтобы добавить в DI (аргумент сборки предназначен для класса, который содержит ваши конфигурации сопоставления, в моем случае это класс MappingProfile).

//add automapper DI
services.AddAutoMapper(typeof(MappingProfile));

В контроллере используйте его, как любой другой объект DI

    [Route("api/[controller]")]
    [ApiController]
    public class AnyController : ControllerBase
    {
        private readonly IMapper _mapper;

        public AnyController(IMapper mapper)
        {
            _mapper = mapper;
        }
        
        public IActionResult Get(int id)
        {
            var entity = repository.Get(id);
            var dto = _mapper.Map(entity);
            
            return Ok(dto);
        }
    }


Мне нравится много ответов, особенно @saineshwar. Я использую .net Core 3.0 с AutoMapper 9.0, поэтому считаю, что пора обновить его ответ.

То, что сработало для меня, было в Startup.ConfigureServices (...) зарегистрируйте службу следующим образом:

    services.AddAutoMapper(cfg => cfg.AddProfile(), 
                               AppDomain.CurrentDomain.GetAssemblies());

Я думаю, что остальная часть ответа @saineshwar остается идеальной. Но если кому-то интересно, мой код контроллера:

[HttpGet("{id}")]
public async Task GetIic(int id)
{
    // _context is a DB provider
    var Iic = await _context.Find(id).ConfigureAwait(false);

    if (Iic == null)
    {
        return NotFound();
    }

    var map = _mapper.Map(Iic);

    return Ok(map);
}

И мой класс отображения:

public class MappingProfile : Profile
{
    public MappingProfile()
    {
        CreateMap()
            .ForMember(dest => dest.DepartmentName, o => o.MapFrom(src => src.Department.Name))
            .ForMember(dest => dest.PortfolioTypeName, o => o.MapFrom(src => src.PortfolioType.Name));
            //.ReverseMap();
    }
}

----- РЕДАКТИРОВАТЬ -----

После прочтения документов, связанных в комментариях Лучиана Баргаоану, я думаю, что лучше немного изменить этот ответ.

Без параметров services.AddAutoMapper () (на который был дан ответ @saineshwar) больше не работает (по крайней мере, для меня). Но если вы используете сборку NuGet AutoMapper.Extensions.Microsoft.DependencyInjection, фреймворк сможет проверять все классы, расширяющие AutoMapper.Profile (например, мой MappingProfile).

Итак, в моем случае, когда класс принадлежит одной и той же исполняющей сборке, регистрацию службы можно сократить до services.AddAutoMapper (System.Reflection.Assembly.GetExecutingAssembly ());
(Более элегантным подходом могло бы быть расширение без параметров с этим кодированием).

Спасибо, Люциан!

Для AutoMapper 9.0.0:

public static IEnumerable GetAutoMapperProfilesFromAllAssemblies()
    {
        foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
        {
            foreach (var aType in assembly.GetTypes())
            {
                if (aType.IsClass && !aType.IsAbstract && aType.IsSubclassOf(typeof(Profile)))
                    yield return aType;
            }
        }
    }

MapperProfile:

public class OrganizationProfile : Profile
{
  public OrganizationProfile()
  {
    CreateMap();
    // Use CreateMap... Etc.. here (Profile methods are the same as configuration methods)
  }
}

В вашем автозагрузке:

services.AddAutoMapper(GetAutoMapperProfilesFromAllAssemblies()
            .ToArray());

В контроллере или сервисе: Инъект маппер:

private readonly IMapper _mapper;

Использование:

var obj = _mapper.Map(sourceObject);

Let’s have a look at how to add Auto mapper into our .NET Core application.

шаг: 1 Первый шаг - установить соответствующий пакет NuGet:

Install-Package AutoMapper.Extensions.Microsoft.DependencyInjection

шаг: 2

После установки необходимого пакета следующим шагом будет настройка служб. Сделаем это в классе Startup.cs:

public void ConfigureServices(IServiceCollection services)
{
    services.AddAutoMapper(typeof(Startup));
    services.AddControllersWithViews();
}

шаг: 3

Приступим к использованию, у нас есть объект домена с именем User:

public class User
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Email { get; set; }
    public string Address { get; set; }
}

На уровне пользовательского интерфейса у нас была бы модель представления для отображения информации о пользователе:

public class UserViewModel
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Email { get; set; }
}

шаг: 4

Хороший способ организовать наши конфигурации сопоставления - использовать профили. Нам нужно создать классы, которые наследуются от класса Profile и поместить конфигурацию в конструктор:

public UserProfile()
{
    CreateMap();
}

шаг: 5

Теперь давайте определим контроллер и воспользуемся только что добавленными возможностями автоматического сопоставления:

public class UserController : Controller
{
    private readonly IMapper _mapper;
    public UserController(IMapper mapper)
    {
        _mapper = mapper;
    }
    public IActionResult Index()
    {
        // Populate the user details from DB
        var user = GetUserDetails();
        UserViewModel userViewModel = _mapper.Map(user);
        return View(userViewModel);
    }
}

Сначала мы вводим объект сопоставления в контроллер. Затем мы вызываем метод Map (), который сопоставляет объект User с объектом UserViewModel. Кроме того, обратите внимание на локальный метод GetUserDetails, который мы используем для локального хранения данных. Вы можете найти его реализацию в нашем исходном коде.

В последних версиях ядра asp.net необходимо использовать следующую инициализацию:

services.AddAutoMapper(typeof(YourMappingProfileClass));

насчет ответа theutz, нет необходимости указывать параметр IMapper mapper в конструкторе контроллеров.

вы можете использовать Mapper, поскольку это статический член в любом месте кода.

public class UserController : Controller {
   public someMethod()
   {
      Mapper.Map(user);
   }
}

Чтобы добавить к тому, что Арве Систад упомянул для тестирования. Если по какой-либо причине вы похожи на меня и хотите сохранить структуру наследования, предоставленную в решении theutz, вы можете настроить MapperConfiguration следующим образом:

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

Я сделал это в NUnit.

Asp.Net Core 2.2 с AutoMapper.Extensions.Microsoft.DependencyInjection.

public class MappingProfile : Profile
{
  public MappingProfile()
  {
      CreateMap();
  }
}

В Startup.cs

services.AddAutoMapper(typeof(List.Handler));

В моем Startup.cs (Core 2.2, Automapper 8.1.1)

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

В моем проекте доступа к данным

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

В моем определении модели

namespace DAL.Models
{
    public class PositionProfile : Profile
    {
        public PositionProfile()
        {
            CreateMap();
        }
    }

    public class Position
    {
        ...
    }

theutz 'ответ здесь очень хороший, я просто хочу добавить это:

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();
}

services.AddAutoMapper (); у меня не сработало. (Я использую Asp.Net Core 2.0)

После настройки, как показано ниже

   var config = new AutoMapper.MapperConfiguration(cfg =>
   {                 
       cfg.CreateMap();
   });

инициализировать маппер IMapper mapper = config.CreateMapper ();

и добавить объект сопоставления к службам как синглтон services.AddSingleton (сопоставитель);

таким образом я могу добавить DI к контроллеру

  private IMapper autoMapper = null;

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

, и я использовал, как показано ниже, в своих методах действий

  ClientCustomer customerObj = autoMapper.Map(customer);

Я использую AutoMapper 6.1.1 и asp.net Core 1.1.2.

Прежде всего, определите классы профиля, унаследованные от класса профиля Automapper. Я создал пустой интерфейс IProfile, цель состоит только в том, чтобы найти классы этого типа.

 открытый класс UserProfile: Профиль, IProfile
    {
        общедоступный UserProfile ()
        {
            CreateMap <Пользователь, Модель пользователя> ();
            CreateMap <Модель пользователя, Пользователь> ();
        }
    }

Теперь создайте отдельный класс, например Mappings

 Отображения общедоступных классов
    {
     общедоступная статическая пустота RegisterMappings ()
     {
       var all =
       сборка
          .GetEntryAssembly ()
          .GetReferencedAssemblies ()
          .Select (Сборка.Загрузка)
          .SelectMany (x => x.DefinedTypes).
          .Where (type => typeof (IProfile) .GetTypeInfo (). IsAssignableFrom (type.AsType ()));

            foreach (всего var ti)
            {
                var t = ti.AsType ();
                если (t.Equals (typeof (IProfile)))
                {
                    Mapper.Initialize (cfg =>
                    {
                        cfg.AddProfiles (t); // Инициализируем каждый класс профиля
                    });
                }
            }
        }

    }

Теперь в веб-проекте MVC Core в файле Startup.cs в конструкторе вызовите класс Mapping, который инициализирует все сопоставления во время приложения. загрузка.

Mappings.RegisterMappings();

Необходимо установить пакет для настройки автомаппера.

dotnet добавить пакет AutoMapper.Extensions.Microsoft.DependencyInjection

После AddAutoMapper будет доступен в сервисах.

public void ConfigureServices(IServiceCollection services)
{
     services.AddAutoMapper(typeof(Startup));
}

Создать сопоставитель из класса Employee в EmployeeDTO.

using AutoMapper;

public class AutomapperProfile: Profile
{
    public AutomapperProfile()
    {
        //Source to destination.
        CreateMap();
    }
}

EmployeeController сопоставляет EmployeeDTo с EmployeeDTo

using System.Collections.Generic;
using AutoMapper;
using Microsoft.AspNetCore.Mvc;

[Route("api/[controller]")]
[ApiController()]
public class EmployeeController : ControllerBase
{
    private readonly IMapper _mapper;

    public EmployeeController(IMapper mapper)
    {
        _mapper = mapper;
    }

    [HttpGet]
    public IEnumerable GetEmployees()
    {
        /* 
        Assume it to be a  service call/database call
        it returns a list of employee, and now we will map it to EmployeeDTO
        */
        var employees = Employee.SetupEmployee();
        var employeeDTO = _mapper.Map>(employees);
        return employeeDTO;

    }
}

Employee.cs для справки

using System.Collections.Generic;

public class Employee
{
    public int EmployeeId { get; set; }
    public string EmployeeName { get; set; }
    public int Salary { get; set; }

    public static IEnumerable SetupEmployee()
    {
        return new List()
        {
            new Employee(){EmployeeId = 1, EmployeeName ="First", Salary=10000},
            new Employee(){EmployeeId = 2, EmployeeName ="Second", Salary=20000},
            new Employee(){EmployeeId = 3, EmployeeName ="Third", Salary=30000},
            new Employee(){EmployeeId = 4, EmployeeName ="Fourth", Salary=40000},
            new Employee(){EmployeeId = 5, EmployeeName ="Fifth", Salary=50000}
        };
    }

}

EmployeeDTO.cs для справки

public class EmployeeDTO
{
    public int EmployeeId { get; set; }
    public string EmployeeName { get; set; }
}

2022 WebDevInsider