如何在 MVC Web API 控制器中使用自动映射程序 10.1.1 ASP.NET?



我正在尝试使用 ASP.NET MVC重新制作我不久前制作的应用程序,但我遇到的问题是由使用最新版本的Automapper引起的。我第一次制作应用程序时遵循了一个教程,在本教程中,我使用的Automapper版本是 4.1.0。

但是,此版本是在 2016 年左右发布的 - 本教程很旧 - 从那时起Automapper发生了很多更改,即许多东西现在已经过时了。

在以前的版本中,您可以使用类中的静态CreateMap方法Mapper但这已经过时了。

这是我使用旧方法的方法。首先,我创建了一个派生自Profile的类来存储我的配置。

public class MappingProfile : Profile
{
public MappingProfile()
{
// Domain to DTO
Mapper.CreateMap<Customer, CustomerDto>();
Mapper.CreateMap<Movie, MovieDto>();
Mapper.CreateMap<MembershipType, MembershipTypeDto>();
Mapper.CreateMap<MembershipTypeDto, MembershipType>();
Mapper.CreateMap<Genre, GenreDto>();
Mapper.CreateMap<GenreDto, Genre>();
// Dto to Domain 
Mapper.CreateMap<CustomerDto, Customer>()
.ForMember(c => c.Id, opt => opt.Ignore());
Mapper.CreateMap<MovieDto, Movie>()
.ForMember(c => c.Id, opt => opt.Ignore());
}
}

接下来,我初始化了Mapper类并在Global.asax.cs中添加了配置文件。

public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
// Here's the line of code I added
Mapper.Initialize(c => c.AddProfile<MappingProfile>());
GlobalConfiguration.Configure(WebApiConfig.Register);
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}

最后,我使用Mapper中的静态Map方法将域对象映射到 DTO 对象,反之亦然,在我的 API 控制器中。顺便说一下,这一切都工作正常。

public IHttpActionResult CreateCustomer(CustomerDto customerDto)
{
if (!ModelState.IsValid)
{
BadRequest();
}
var customer = Mapper.Map<CustomerDto, Customer>(customerDto);
_context.Customers.Add(customer);
_context.SaveChanges();
customerDto.Id = customer.Id;
return Created(new Uri(Request.RequestUri + "/" + customer.Id ), customerDto);
}

最新的自动映射器文档建议您使用MapperConfigurationCreateMap为域和 DTO 对象创建映射,并且每个 AppDomain 只需要一个应在启动期间实例化的MapperConfiguration实例。

我继续并再次创建了一个MappingProfile来存储我的配置(按照文档的建议),并将此配置包含在Global.asax.csApplication_Start()中,这是 MVC 应用程序的启动。

public class MappingProfile : Profile
{
public MappingProfile()
{
CreateMap<Customer, CustomerDto>();
CreateMap<CustomerDto, Customer>();
}
}
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
// This is the new way of creating a MapperConfiguration 
var configuration = new MapperConfiguration(cfg =>
{
cfg.AddProfile<MappingProfile>();
});
IMapper mapper = configuration.CreateMapper();
GlobalConfiguration.Configure(WebApiConfig.Register);
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
UnityConfig.RegisterComponents();
}
}

此时,文档说您可以使用依赖注入来注入创建的IMapper实例。 这就是我陷入困境并遇到错误的地方。

该文档很好地涵盖了 ASP.NET Core,解释了如何使用依赖注入,因此我尝试将此方法与UnityConfig一起使用,其中我在那里创建了MapperConfiguration并注册了IMapper的实例,然后尝试将其注入到我的Web API控制器中,如下所示:

public static class UnityConfig
{
public static void RegisterComponents()
{
var container = new UnityContainer();
var configuration = new MapperConfiguration(cfg =>
{
cfg.AddProfile<MappingProfile>();
});
IMapper mapper = configuration.CreateMapper();
container.RegisterInstance(mapper);
// register all your components with the container here
// it is NOT necessary to register your controllers

// e.g. container.RegisterType<ITestService, TestService>();

DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}
}
public class MvcApplication : System.Web.HttpApplication
{

protected void Application_Start()
{            
GlobalConfiguration.Configure(WebApiConfig.Register);
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
// I registered the components here inside Global.asax.cs
UnityConfig.RegisterComponents();
}
}

这是我尝试通过依赖注入使用实例的地方。

public class CustomersController : ApiController
{
private ApplicationDbContext _context;
private readonly IMapper _mapper;
public CustomersController()
{
_context = new ApplicationDbContext();
}
public CustomersController(IMapper mapper)
{
_mapper = mapper;
}
// GET /api/customers
public IHttpActionResult GetCustomers()
{
var customersDto = _context.Customers
.Include(c => c.MembershipType)
.ToList()
.Select(_mapper.Map<Customer, CustomerDto>);
return Ok(customersDto);
}
// Remaining code omitted because it's unnecessary

调试时遇到的错误是NullReferenceException.在"监视"窗口中,我注意到_mapper为空,但是,对象确实从数据库加载。问题是即使在使用 DI 后_mapper仍然为空。

有人可以解释一下为什么在 ASP.NET MVC Web API 控制器中以这种方式使用此版本的Automapper是空的和潜在的修复/提示?

经过大量的阅读和研究,我终于弄清楚了我哪里出错了。我相信Unity.Mvc5适用于常规控制器,而不是 API 控制器。

出于这个原因,我添加了一个单独的软件包,Unity.AspNet.WebApi,它带有不同的Unity.Config.cs。添加包时出现提示,询问我是否要覆盖上一个Unity.Config.cs(来自Unity.Mvc5),我选择了是。

从这里,我将我的配置添加到此文件,注册了实例,然后就可以开始了。

这个视频很好地解释了整个事情: https://youtu.be/c38krTX0jeo

最新更新