【问题标题】:How do I use Automapper 10.1.1 in ASP.NET MVC Web API controller?如何在 ASP.NET MVC Web API 控制器中使用 Automapper 10.1.1?
【发布时间】: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 建议您使用 MapperConfigurationCreateMap 为域和 DTO 对象创建一个映射,并且每个 AppDomain 只需要一个应该在启动期间实例化的 MapperConfiguration 实例。

我继续创建了一个MappingProfile 来存储我的配置(as recommended by the documentation) 并将此配置包含在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的实例,然后尝试将其注入我的网络 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


【解决方案1】:

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

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

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

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

【讨论】:

    猜你喜欢
    • 2018-06-18
    • 2016-05-20
    • 1970-01-01
    • 2019-08-10
    • 2017-07-02
    • 2012-09-04
    • 2017-05-18
    • 1970-01-01
    • 2013-04-14
    相关资源
    最近更新 更多