Настройка 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);
}
Он просто не работает вообще... Мне нужно пропустить какой-то шаг или сделать что-то не так.
Ответы
Ответ 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.
}