Подтвердить что ты не робот

Настройка AutoMapper 4.2 со встроенным IoC в ASP.NET Core 1.0 MVC6

Я пытаюсь выяснить, как правильно настроить AutoMapper в моем файле Startup.cs приложения, а затем использовать его во всем приложении.

Я пытаюсь использовать эту документацию, которая несколько объясняет, как все еще дать AutoMapper статическое ощущение без старого статического API. В этом примере используется StructureMap.

Я хотел бы знать, как я могу сделать что-то подобное, но в приложении Core 1.0, используя встроенный контейнер сервисов.

Я предполагаю, что в функции Configure я бы сконфигурировал AutoMapper, а затем в функции ConfigureServices я бы добавил его как переходный процесс.

В конечном итоге я предполагаю, что самый чистый и правильный способ сделать это - использовать инъекцию зависимостей. Вот моя текущая попытка, но она не работает:

Startup.cs

public IMapper Mapper { get; set; }
private MapperConfiguration MapperConfiguration { get; set; }
public void ConfigureServices(IServiceCollection services)
{
     services.AddTransient<IMapper, Mapper>();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    MapperConfiguration MapperConfiguration = new MapperConfiguration(cfg =>
    {
        cfg.CreateMap<Product, ProductViewModel>().ReverseMap();
    });

    Mapper = MapperConfiguration.CreateMapper();
}

В моем контроллере

private IMapper _mapper { get; set; }
// Constructor
public ProductsController(IMapper mapper)
{
    _mapper = mapper;
}

public IActionResult Create(ProductViewModel vm)
{
    Product product = _mapper.Map<ProductViewModel, Product>(vm);
}

Он просто не работает вообще... Мне нужно пропустить какой-то шаг или сделать что-то не так.

4b9b3361

Ответ 1

Этот ответ подходит к подходу MVC 6 немного ближе к уровню контроллера:

Я перешел из AutoMapper 4.1.1 в 4.2.0, имел несколько проблем, выясняя тонкости, но попал туда в конце.

Сначала я разделил сборку профиля AutoMapper в новый класс (см. ниже), чтобы сохранить засорение класса Startup.

using AutoMapper;
using YourModels;
using YourViewModels;

namespace YourNamespace
{
    public class AutoMapperProfileConfiguration : Profile
    {
        protected override void Configure()
        {
            CreateMap<Application, ApplicationViewModel>();
            CreateMap<ApplicationViewModel, Application>();
            ...
        }
    }
}

Я внес следующие изменения в класс Startup.

Я добавил переменную частного члена типа MapperConfiguration.

private MapperConfiguration _mapperConfiguration { get; set; }

В конструкторе Startup я добавил следующий код для создания нового профиля AutoMapper.

_mapperConfiguration = new MapperConfiguration(cfg =>
{
    cfg.AddProfile(new AutoMapperProfileConfiguration());
});

В ConfigureServices() я опустил свой новый профиль AutoMapper в Singleton.

services.AddSingleton<IMapper>(sp => _mapperConfiguration.CreateMapper());

Это была просто простая операция, чтобы ввести соответствующие контроллеры.

using AutoMapper;
using ...

namespace YourNamespace
{
    public class ApplicationsController : BaseController
    {
        [FromServices]
        private IMapper _mapper { get; set; }

        [FromServices]
        private IApplicationRepository _applicationRepository { get; set; }

        public ApplicationsController(
            IMapper mapper,
            IApplicationRepository applicationRepository)
        {
            _mapper = mapper;
            _applicationRepository = applicationRepository;
        }

        // GET: Applications
        public async Task<IActionResult> Index()
        {
            IEnumerable<Application> applications = await _applicationRepository.GetForIdAsync(...);

            if (applications == null)
                return HttpNotFound();

            List<ApplicationViewModel> viewModel = _mapper.Map<List<ApplicationViewModel>>(applications);

            return View(viewModel);
        }

        ...
}

Спасибо Rexebin за https://pintoservice.wordpress.com/2016/01/31/dependency-injection-for-automapper-4-2-in-asp-net-vnext-mvc-project/ за его пост, которые помогают изо всех сил.

Ответ 2

Вы также можете использовать пакет расширения от создателя automapper.

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

https://github.com/AutoMapper/AutoMapper.Extensions.Microsoft.DependencyInjection

https://www.nuget.org/packages/AutoMapper.Extensions.Microsoft.DependencyInjection/

public void ConfigureServices(IServiceCollection services)
{
    //configure DI
    services.AddTransient<IFoo, Foo>();

    //Add automapper - scans for Profiles
    services.AddAutoMapper();
    //or specify
    services.AddAutoMapper(cfg =>
    {
        cfg.AddProfile<ViewModelProfile>();
        ...
    });
    ...

Ответ 3

В своих ConfigurationServices вы можете создать экземпляр MapperConfiguration, а затем создать свои карты и добавить их.

public void ConfigureServices(IServiceCollection services)
{     
    MapperConfiguration configuration = new MapperConfiguration(cfg =>
    {
       cfg.AddProfile<MappingProfile.Profile1>();
       cfg.AddProfile<MappingProfile.Profile2>();
    });

    services.AddInstance(typeof (IMapper), configuration.CreateMapper());
}

Затем вы просто вводите IMapper в свой конструктор и карту

public class Handler
{
      private readonly ProfileContext _db;
      private readonly IMapper _mapper;

      public Handler(ProfileContext db, IMapper mapper)
      {
          _db = db;
          _mapper = mapper;
      }

      public void Handle(Profile1 request)
      {

          ProfileModel profile = _mapper.Map<Profile1, ProfileModel>(request);

          _db.Profiles.Add(profile);

          try
          {
              db.SaveChanges();
          }
          catch (Exception ex)
          {

              throw;
          }

          return profile;
      }
}

Ответ 4

Опубликованный ответ - отличное решение, но я решил, что дам вам знать, как я это делаю сейчас с Core 1.0 и AutoMapper v5.1.1. Я чувствую, что это очень хороший подход и легко понять.

В Startup.cs в начале метода Configure просто напишите следующий код, чтобы инициализировать ваши сопоставления:

Mapper.Initialize(config =>
{
     config.CreateMap<ProductViewModel, Product>().ReverseMap();
     config.CreateMap<CustomerViewModel, Customer>().ReverseMap();
});

Затем в вашем контроллере или любой другой части вашего кода, где вам нужно отобразить:

Mapper.Map<Product>(productViewModel);

Ответ 5

Я просто экспериментирую с переносом веб-API с ядра .net 4.5 на .net и нуждаюсь в этом. Вы были очень близки, так как @DavidGouge предложил вам зарегистрировать экземпляр сопоставления, который вы создали в МОК. Поэтому конфигурацию AutoMapper необходимо выполнить в ConfigureServices. (Включили в строку здесь, но в моем проекте он вызывает метод в классе AutoMapperConfiguration, поэтому Startup остается как можно более чистым, так же, как и при регистрации IOC). Затем IMapper будет правильно заполнен в вашем контроллере.

Startup.cs становится

   public IMapper Mapper { get; set; }
   private MapperConfiguration MapperConfiguration { get; set; }
   public void ConfigureServices(IServiceCollection services)
   {
        MapperConfiguration MapperConfiguration = new MapperConfiguration(cfg =>
        {
            cfg.CreateMap<Product, ProductViewModel>().ReverseMap();
        });

        Mapper = MapperConfiguration.CreateMapper();

        services.AddInstance(Mapper);
    }
    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        // AutoMapper Configuration moved out of here.
    }