在ASP.NET Core 1.0 MVC6中使用内置的IoC配置AutoMapper 4.2

22

我正在尝试找出在应用程序的Startup.cs文件中正确配置AutoMapper并在整个应用程序中使用它的方法。

我正在尝试使用这份文档,其中有些解释如何仍然使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);
}

它根本就不起作用...我一定漏掉了某些步骤或者做错了什么。


我对此问题没有完整的答案(我自己也在苦苦挣扎!),但是在您的AddTransient中,第二个泛型参数是Mapper的类型,而不是您使用CreateMapper创建的Mapper实例。我猜想它将会是类似于services.AddInstance的东西。 - DavidGouge
5个回答

37

这个答案更适合MVC 6方法,尤其是在控制器层面上:

我从AutoMapper 4.1.1迁移到了4.2.0版本,遇到了一些细节问题,但最终解决了。

首先,我将AutoMapper Profile构建分离到一个新的类中(见下文),以免阻塞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 Profile。
_mapperConfiguration = new MapperConfiguration(cfg =>
{
    cfg.AddProfile(new AutoMapperProfileConfiguration());
});

ConfigureServices() 中,我将我的新 AutoMapper Profile 放入了一个 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/发布的文章,对我有巨大的帮助。


7
你也可以使用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>();
        ...
    });
    ...

4
在你的 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;
      }
}

3
已发布的答案是一个很好的解决方案,但我想让您知道我目前在使用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);

0

我只是在尝试将一个Web API从.net 4.5迁移到.net core,并需要这个。你很接近了,正如@DavidGouge建议的那样,你需要在IOC中注册你创建的映射器实例。因此,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.
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接