【发布时间】:2021-08-13 03:26:01
【问题描述】:
我正在尝试重新制作我不久前使用 ASP.NET MVC 制作的应用程序,但我遇到的问题是由使用最新版本的 Automapper 引起的。我第一次做应用时是按照教程做的,在这个教程中,我使用的Automapper的版本是4.1.0。
然而,这个版本是在 2016 年左右发布的 - 教程已经很老了 - 从那时起,Automapper 发生了很多变化,即很多东西现在已经过时了。
在以前的版本中,您可以使用 Mapper 类中的静态 CreateMap 方法,但现在已经过时了。
这是我使用旧方法的方法。首先,我创建了一个派生自 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 方法将我的域对象映射到我的API 控制器中的DTO 对象,反之亦然。顺便说一句,这一切都很好。
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);
}
latest Automapper documentation 建议您使用 MapperConfiguration 和 CreateMap 为域和 DTO 对象创建一个映射,并且每个 AppDomain 只需要一个应该在启动期间实例化的 MapperConfiguration 实例。
我继续创建了一个MappingProfile 来存储我的配置(as recommended by the documentation) 并将此配置包含在Global.asax.cs 的Application_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的实例,然后尝试将其注入我的网络 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。在 Watch 窗口中,我注意到 _mapper 为空,但是,对象确实是从数据库中加载的。问题是 _mapper 即使在使用 DI 后仍然为空。
有人可以解释为什么在 ASP.NET MVC Web API 控制器中以这种方式使用此版本的Automapper 是无效的以及潜在的修复/提示吗?
【问题讨论】:
-
您可以在任何应用程序中使用 MS DI,而不仅仅是 ASP.NET Core,然后您可以在 AM 中使用内置的 DI 包。
-
微软官网的文档只涉及.NET Core和Console应用,不涉及MVC。您是否有任何指向 MVC 中 Automapper DI 文档的链接,特别是 @LucianBargaoanu?
-
不需要此类文档。 MS DI 包(和 AM DI 包)可以像任何其他 DI 包一样在 MVC 中使用。没什么特别的。
-
好的。根据我的问题中提供的方法,我哪里出错了?
标签: c# asp.net asp.net-mvc asp.net-core-webapi automapper-10