ChatGPT解决这个技术问题 Extra ChatGPT

如何在 ASP.NET Core 中设置 Automapper

我在 .NET 方面相对较新,我决定解决 .NET Core 而不是学习“旧方法”。我找到了一篇关于 setting up AutoMapper for .NET Core here 的详细文章,但是对于新手有没有更简单的演练?

对于较新版本的核心 (>v1),请查看 @Saineshwar 的回答 stackoverflow.com/a/53455699/833878
带有示例的完整答案 click this link
如果您的项目中已经有 Identity,那么您已经通过它隐式引用了 Automapper。添加 AutoMapper.Extensions.Microsoft.DependencyInjection 可以将依赖项更改为更高版本的 AutoMapper 并破坏身份。请注意选择具有相同依赖关系的 DI 版本。另请参阅stackoverflow.com/questions/63519439/…
需要熟悉 AutoMapper 的人使用指南jimmybogard.com/automapper-usage-guidelines

W
Wai Ha Lee

我想到了!这是详细信息:

通过 NuGet 将主 AutoMapper 包添加到您的解决方案中。通过 NuGet 将 AutoMapper 依赖注入包添加到您的解决方案中。为映射配置文件创建一个新类。 (我在主解决方案目录中创建了一个名为 MappingProfile.cs 的类并添加了以下代码。)我将使用 User 和 UserDto 对象作为示例。 public class MappingProfile : Profile { public MappingProfile() { // 添加尽可能多的这些行来映射您的对象 CreateMap(); CreateMap(); } } 然后在 Startup.cs 中添加 AutoMapperConfiguration 如下所示: public void ConfigureServices(IServiceCollection services) { // .... 忽略此之前的代码 // Auto Mapper Configurations var mapperConfig = new MapperConfiguration(mc => { mc. AddProfile(new MappingProfile()); }); IMapper 映射器 = mapperConfig.CreateMapper(); services.AddSingleton(映射器);服务.AddMvc();要在代码中调用映射对象,请执行以下操作: public class UserController : Controller { // 创建一个字段来存储映射器对象 private readonly IMapper _mapper; // 在构造函数中为依赖注入分配对象 public UserController(IMapper mapper) { _mapper = mapper; } public async Task Edit(string id) { // 实例化源对象 // (从数据库或您的代码要求的任何地方获取它) var user = await _context.Users .SingleOrDefaultAsync(u => u.Id = =身份证); // 实例化映射的数据传输对象 // 使用您存储在私有字段中的映射器。 // 源对象的类型是第一个类型参数 // 而目标的类型是第二个。 // 将刚刚在上面实例化的源对象作为参数传递给 _mapper.Map<>() 方法。 var model = _mapper.Map(user); // .... 之后做任何你想做的事! } }


链接的详细文章 lostechies.com/jimmybogard/2016/07/20/… 解释了 Profile 类的位置
@theutz您可以将这两条 CreateMap 行与 .ReverseMap() 合并到最后。也许评论它,但我发现它更直观。
在第 3 步中提及添加“使用 AutoMapper”可能会有所帮助;在顶部,以便导入扩展方法。
这适用于 .net core 1.1,一旦我升级到 .net core 2.0 就不再适用了。我想,我需要明确指定逻辑配置文件类程序集。仍在研究如何实现这一点。更新:啊,答案取决于您的评论,我必须通过 typeof 类,这是我的个人资料。 // services.AddAutoMapper(typeof(Startup)); // <-- 较新的自动映射器版本使用此签名
在 AutoMapper v8 和 Dependency Injection v5 add on 中,唯一需要的是 services.AddAutoMapper(); Startup 类的 ConfigureServices 方法中的行。对我来说,它甚至能够在依赖类库项目中找到 Profile 类。
S
Saineshwar Bageri - MVP

将 AutoMapper 与 ASP.NET Core 一起使用的步骤。

步骤 1. 从 NuGet 包安装 AutoMapper.Extensions.Microsoft.DependencyInjection。

https://i.stack.imgur.com/NLEBL.png

步骤 2. 在解决方案中创建一个文件夹以保留名称为“映射”的映射。

https://i.stack.imgur.com/6wOpQ.png

步骤 3. 添加 Mapping 文件夹后,我们添加了一个名为“MappingProfile”的类,该名称可以是任何独特且易于理解的名称。

在本课程中,我们将维护所有映射。

https://i.stack.imgur.com/GSeup.png

步骤 4. 在启动“ConfigureServices”中初始化 Mapper

在启动类中,我们需要初始化我们创建的配置文件并注册 AutoMapper 服务。

  Mapper.Initialize(cfg => cfg.AddProfile<MappingProfile>());

  services.AddAutoMapper();

代码片段显示我们需要初始化和注册 AutoMapper 的 ConfigureServices 方法。

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }


    public void ConfigureServices(IServiceCollection services)
    {
        services.Configure<CookiePolicyOptions>(options =>
        {
            // This lambda determines whether user consent for non-essential cookies is needed for a given request.
            options.CheckConsentNeeded = context => true;
            options.MinimumSameSitePolicy = SameSiteMode.None;
        });


        // Start Registering and Initializing AutoMapper

        Mapper.Initialize(cfg => cfg.AddProfile<MappingProfile>());
        services.AddAutoMapper();

        // End Registering and Initializing AutoMapper

        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

    }}

步骤 5. 获取输出。

要获取映射结果,我们需要调用 AutoMapper.Mapper.Map 并传递正确的目标和源。

AutoMapper.Mapper.Map<Destination>(source);

代码片段

    [HttpPost]
    public void Post([FromBody] SchemeMasterViewModel schemeMaster)
    {
        if (ModelState.IsValid)
        {
            var mappedresult = AutoMapper.Mapper.Map<SchemeMaster>(schemeMaster);
        }
    }

我收到以下错误:'Mapper' does not contain a definition for 'initialize'。我正在使用 AutoMapper.Extensions.Microsoft.DependencyInjection 版本 7.0.0
超级详细的答案。谢谢你,先生。
如果您使用的是 ASP.NET CORE 3.0,请查看本教程如何在 ASP.NET Core 3.0 中设置 AutoMapper tutexchange.com/how-to-set-up-automapper-in-asp-net-core-3-0
如果我想在调用 AddAutoMapper 之前在 MapperConfiguration 上调用 CompileMappings*( 怎么办?
R
RJFalconer

我想扩展@theutz 的答案——即这一行:

// services.AddAutoMapper(typeof(Startup));  // <-- newer automapper version uses this signature.

AutoMapper.Extensions.Microsoft.DependencyInjection 3.2.0 版中有一个错误(可能)。 (我使用的是 .NET Core 2.0)

这在 this GitHub 问题中得到解决。如果您的继承 AutoMapper 的 Profile 类的类存在于您的 Startup 类所在的程序集之外,如果您的 AutoMapper 注入如下所示,则它们可能不会被注册:

services.AddAutoMapper();

除非您明确指定要搜索 AutoMapper 配置文件的程序集。

可以在您的 Startup.ConfigureServices 中这样做:

services.AddAutoMapper(<assembies> or <type_in_assemblies>);

其中“assemblies”和“type_in_assemblies”指向在您的应用程序中指定 Profile 类的程序集。例如:

services.AddAutoMapper(typeof(ProfileInOtherAssembly), typeof(ProfileInYetAnotherAssembly));

假设(我强调这个词)是由于以下无参数重载的实现(来自 GitHub 的源代码):

public static IServiceCollection AddAutoMapper(this IServiceCollection services)
{
     return services.AddAutoMapper(null, AppDomain.CurrentDomain.GetAssemblies());
}

我们依赖 CLR 已经 JITed 程序集,其中包含 AutoMapper 配置文件,这些配置文件可能是也可能不是真的,因为它们只在需要时才被 jit(更多细节在 this StackOverflow 问题中)。


这是最新版本 AutoMapper 和 AspNetCore 的正确答案
这是我正在寻找 AutoMapper 8.1(最新版本)的答案
如果我想在调用 AddAutoMapper 之前在 MapperConfiguration 上调用 CompileMappings*( 怎么办?
仅供参考:1)这个答案说 theutz 答案引用了 AddAutoMapper() 但它没有,2)无参数的 AddAutoMapper() 扩展方法已被删除;我正在使用版本 11.0 ... FWIW 自动映射器 API 似乎随着时间的推移发生了很大变化(这是一个 PITA),我认为 theutz 在某个时候更新了他的答案
A
Arve Systad

theutz 在这里的回答非常好,我只想补充一下:

如果您让映射配置文件从 MapperConfigurationExpression 而不是 Profile 继承,您可以非常简单地添加一个测试来验证您的映射设置,这总是很方便:

[Fact]
public void MappingProfile_VerifyMappings()
{
    var mappingProfile = new MappingProfile();

    var config = new MapperConfiguration(mappingProfile);
    var mapper = new Mapper(config);

    (mapper as IMapper).ConfigurationProvider.AssertConfigurationIsValid();
}

我收到一个错误:“AutoMapper 扩展依赖注入与 asp.net core 1.1 不兼容”。请帮忙!
似乎“验证”的定义有待商榷。当设计省略某些属性以防止映射时,这会爆炸。
如果您不想映射属性,请使用 .Ignore() 进行设置。这样,它会迫使您积极考虑处理每个案例 - 确保您在进行更改时不会错过任何东西。超级实用,真的。所以是的,验证测试是一个比许多人意识到的更大的安全网。它不是万无一失的,但它会照顾前 90%。
C
Coy Meeks

我以这种方式解决了它(类似于上面,但我觉得它是一个更清洁的解决方案)适用于 .NET Core 3.x

创建 MappingProfile.cs 类并使用 Maps 填充构造函数(我计划使用单个类来保存我的所有映射)

    public class MappingProfile : Profile
    {
        public MappingProfile()
        {
            CreateMap<Source, Dest>().ReverseMap();
        }
    }

在 Startup.cs 中,添加以下内容以添加到 DI(程序集 arg 用于保存映射配置的类,在我的情况下,它是 MappingProfile 类)。

//add automapper DI
services.AddAutoMapper(typeof(MappingProfile));

在 Controller 中,像使用任何其他 DI 对象一样使用它

    [Route("api/[controller]")]
    [ApiController]
    public class AnyController : ControllerBase
    {
        private readonly IMapper _mapper;

        public AnyController(IMapper mapper)
        {
            _mapper = mapper;
        }
        
        public IActionResult Get(int id)
        {
            var entity = repository.Get(id);
            var dto = _mapper.Map<Dest>(entity);
            
            return Ok(dto);
        }
    }



我喜欢你的回答。我认为 this answer 中所示的用 new Type[]{} 包装 MappingProfiles 是不必要的。
不要忘记在开头安装 DI:AutoMapper.Extensions.Microsoft.DependencyInjection
您还需要在您的 Startup.cs 中添加 services.AddScoped<IMapper, Mapper>();,IMapper 是 AutoMapper 接口,Mapper 来自 AutoMapper,所以我们不需要做任何事情
m
martcs

在最新版本的 asp.net core 中,您应该使用以下初始化:

services.AddAutoMapper(typeof(YourMappingProfileClass));

谢谢。这行得通。我正在使用网络核心 3.0。我的对象甚至并不复杂。它只有 2 个属性,id 和 name。出于某种原因,在一个 Youtube 教程中,我遵循了该项目 100% 包括这一行,AppDomain.CurrentDomain.GetAssemblies(),并且它有效。然而,当我从头开始。您的解决方案有效
我们可以使用 services.AddAutoMapper(Assembly.GetExecutingAssembly()); 获取从该程序集中的 Profile 类派生的所有映射类。
V
Vic

我喜欢很多答案,尤其是@saineshwar 的答案。我正在使用 .net Core 3.0 和 AutoMapper 9.0,所以我觉得是时候更新它的答案了。

对我有用的是 Startup.ConfigureServices(...) 以这种方式注册服务:

    services.AddAutoMapper(cfg => cfg.AddProfile<MappingProfile>(), 
                               AppDomain.CurrentDomain.GetAssemblies());

我认为@saineshwar 的其余答案保持完美。但如果有人感兴趣,我的控制器代码是:

[HttpGet("{id}")]
public async Task<ActionResult> GetIic(int id)
{
    // _context is a DB provider
    var Iic = await _context.Find(id).ConfigureAwait(false);

    if (Iic == null)
    {
        return NotFound();
    }

    var map = _mapper.Map<IicVM>(Iic);

    return Ok(map);
}

还有我的映射类:

public class MappingProfile : Profile
{
    public MappingProfile()
    {
        CreateMap<Iic, IicVM>()
            .ForMember(dest => dest.DepartmentName, o => o.MapFrom(src => src.Department.Name))
            .ForMember(dest => dest.PortfolioTypeName, o => o.MapFrom(src => src.PortfolioType.Name));
            //.ReverseMap();
    }
}

- - - 编辑 - - -

在阅读了 Lucian Bargaoanu 评论中链接的文档后,我认为最好稍微改变一下这个答案。

无参数的 services.AddAutoMapper() (有@saineshwar 的答案)不再起作用(至少对我而言)。但是,如果您使用 NuGet 程序集 AutoMapper.Extensions.Microsoft.DependencyInjection,该框架能够检查所有扩展 AutoMapper.Profile 的类(例如我的 MappingProfile)。

因此,在我的例子中,如果类属于同一个执行程序集,则服务注册可以缩短为 services.AddAutoMapper(System.Reflection.Assembly.GetExecutingAssembly());
(更优雅的方法可能是使用此编码进行无参数扩展)。

谢谢,卢锡安!


B
Brian Rice

在我的 Startup.cs (Core 2.2, Automapper 8.1.1)

services.AddAutoMapper(new Type[] { typeof(DAL.MapperProfile) });            

在我的数据访问项目中

namespace DAL
{
    public class MapperProfile : Profile
    {
        // place holder for AddAutoMapper (to bring in the DAL assembly)
    }
}

在我的模型定义中

namespace DAL.Models
{
    public class PositionProfile : Profile
    {
        public PositionProfile()
        {
            CreateMap<Position, PositionDto_v1>();
        }
    }

    public class Position
    {
        ...
    }

为什么不直接使用 services.AddAutoMapper( typeof(DAL.MapperProfile) ); 而不是 services.AddAutoMapper(new Type[] { typeof(DAL.MapperProfile) });
N
Nicolae Lupei

对于 AutoMapper 9.0.0:

public static IEnumerable<Type> GetAutoMapperProfilesFromAllAssemblies()
    {
        foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
        {
            foreach (var aType in assembly.GetTypes())
            {
                if (aType.IsClass && !aType.IsAbstract && aType.IsSubclassOf(typeof(Profile)))
                    yield return aType;
            }
        }
    }

映射器简介:

public class OrganizationProfile : Profile
{
  public OrganizationProfile()
  {
    CreateMap<Foo, FooDto>();
    // Use CreateMap... Etc.. here (Profile methods are the same as configuration methods)
  }
}

在您的启动中:

services.AddAutoMapper(GetAutoMapperProfilesFromAllAssemblies()
            .ToArray());

在控制器或服务中:注入映射器:

private readonly IMapper _mapper;

用法:

var obj = _mapper.Map<TDest>(sourceObject);

真棒@Nicolae Lupei
A
Aman singh Parihar

需要安装一个包来设置自动映射器。

dotnet add package AutoMapper.Extensions.Microsoft.DependencyInjection

之后 AddAutoMapper 将在服务中可用。

public void ConfigureServices(IServiceCollection services)
{
     services.AddAutoMapper(typeof(Startup));
}

创建从 Employee 类到 EmployeeDTO 的映射器。

using AutoMapper;

public class AutomapperProfile: Profile
{
    public AutomapperProfile()
    {
        //Source to destination.
        CreateMap<Employee,EmployeeDTO>();
    }
}

EmployeeController 从 Employee 映射到 EmployeeDTo

using System.Collections.Generic;
using AutoMapper;
using Microsoft.AspNetCore.Mvc;

[Route("api/[controller]")]
[ApiController()]
public class EmployeeController : ControllerBase
{
    private readonly IMapper _mapper;

    public EmployeeController(IMapper mapper)
    {
        _mapper = mapper;
    }

    [HttpGet]
    public IEnumerable<EmployeeDTO> GetEmployees()
    {
        /* 
        Assume it to be a  service call/database call
        it returns a list of employee, and now we will map it to EmployeeDTO
        */
        var employees = Employee.SetupEmployee();
        var employeeDTO = _mapper.Map<IEnumerable<EmployeeDTO>>(employees);
        return employeeDTO;

    }
}

Employee.cs 供参考

using System.Collections.Generic;

public class Employee
{
    public int EmployeeId { get; set; }
    public string EmployeeName { get; set; }
    public int Salary { get; set; }

    public static IEnumerable<Employee> SetupEmployee()
    {
        return new List<Employee>()
        {
            new Employee(){EmployeeId = 1, EmployeeName ="First", Salary=10000},
            new Employee(){EmployeeId = 2, EmployeeName ="Second", Salary=20000},
            new Employee(){EmployeeId = 3, EmployeeName ="Third", Salary=30000},
            new Employee(){EmployeeId = 4, EmployeeName ="Fourth", Salary=40000},
            new Employee(){EmployeeId = 5, EmployeeName ="Fifth", Salary=50000}
        };
    }

}

EmployeeDTO.cs 供参考

public class EmployeeDTO
{
    public int EmployeeId { get; set; }
    public string EmployeeName { get; set; }
}

R
Roy Scheffers

我正在使用 AutoMapper 6.1.1 和 asp.net Core 1.1.2。

首先,定义Automapper的Profile Class继承的Profile类。我创建了一个空的IProfile接口,目的只是为了找到这个类型的类。

 public class UserProfile : Profile, IProfile
    {
        public UserProfile()
        {
            CreateMap<User, UserModel>();
            CreateMap<UserModel, User>();
        }
    }

现在创建一个单独的类,例如 Mappings

 public class Mappings
    {
     public static void RegisterMappings()
     {            
       var all =
       Assembly
          .GetEntryAssembly()
          .GetReferencedAssemblies()
          .Select(Assembly.Load)
          .SelectMany(x => x.DefinedTypes)
          .Where(type => typeof(IProfile).GetTypeInfo().IsAssignableFrom(type.AsType()));

            foreach (var ti in all)
            {
                var t = ti.AsType();
                if (t.Equals(typeof(IProfile)))
                {
                    Mapper.Initialize(cfg =>
                    {
                        cfg.AddProfiles(t); // Initialise each Profile classe
                    });
                }
            }         
        }

    }

现在在 Startup.cs 文件的 MVC Core Web 项目中,在构造函数中调用 Mapping 类,该类将在应用程序加载时初始化所有映射。

Mappings.RegisterMappings();

您可以从配置文件类创建一个子类,并且在程序运行时 services.AddAutoMapper();代码行 automapper 会自动识别它们。
如果您使用 nuget 中提供的 AutoMapper.Extensions.Microsoft.DependancyInjection,我认为这是不必要的。
d
dalcam

对于 ASP.NET Core(使用 2.0+ 和 3.0 测试),如果您更喜欢阅读源文档:https://github.com/AutoMapper/AutoMapper.Extensions.Microsoft.DependencyInjection/blob/master/README.md

否则,请遵循以下 4 个步骤:

从 nuget 安装 AutoMapper.Extensions.Microsoft.DependancyInjection。只需添加一些配置文件类。然后将以下内容添加到您的 startup.cs 类中。 services.AddAutoMapper(OneOfYourProfileClassNamesHere) 然后只需将 IMapper 注入您的控制器或您需要的任何地方:

public class EmployeesController {

    private readonly IMapper _mapper;

    public EmployeesController(IMapper mapper){

        _mapper = mapper;
    }

如果你现在想简单地使用 ProjectTo 它:

var customers = await dbContext.Customers.ProjectTo<CustomerDto>(_mapper.ConfigurationProvider).ToListAsync()

如果我想在调用 AddAutoMapper 之前在 MapperConfiguration 上调用 CompileMappings*( 怎么办?
B
Bilawal Khan

让我们看看如何将 Auto mapper 添加到我们的 .NET Core 应用程序中。

step: 1 第一步是安装对应的NuGet包:

Install-Package AutoMapper.Extensions.Microsoft.DependencyInjection

第2步

安装所需的软件包后,下一步是配置服务。让我们在 Startup.cs 类中进行:

public void ConfigureServices(IServiceCollection services)
{
    services.AddAutoMapper(typeof(Startup));
    services.AddControllersWithViews();
}

步骤:3

让我们开始使用我们有一个名为 User 的域对象:

public class User
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Email { get; set; }
    public string Address { get; set; }
}

在 UI 层,我们将有一个 View Model 来显示用户信息:

public class UserViewModel
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Email { get; set; }
}

第4步

组织映射配置的一个好方法是使用 Profiles。我们需要创建继承自 Profile 类的类并将配置放入构造函数中:

public UserProfile()
{
    CreateMap<User, UserViewModel>();
}

步数:5

现在,让我们定义一个控制器并使用我们刚刚添加的自动映射功能:

public class UserController : Controller
{
    private readonly IMapper _mapper;
    public UserController(IMapper mapper)
    {
        _mapper = mapper;
    }
    public IActionResult Index()
    {
        // Populate the user details from DB
        var user = GetUserDetails();
        UserViewModel userViewModel = _mapper.Map<UserViewModel>(user);
        return View(userViewModel);
    }
}

首先,我们将映射器对象注入控制器。然后,我们调用 Map() 方法,该方法将 User 对象映射到 UserViewModel 对象。此外,请注意我们用于本地数据存储的本地方法 GetUserDetails。您可以在我们的源代码中找到它的实现。


T
Tachyon

在 .NET 6 中,您需要将以下内容添加到 Program.cs 文件中:

builder.Services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());

S
Sras

带有 AutoMapper.Extensions.Microsoft.DependencyInjection 的 Asp.Net Core 2.2。

public class MappingProfile : Profile
{
  public MappingProfile()
  {
      CreateMap<Domain, DomainDto>();
  }
}

在 Startup.cs

services.AddAutoMapper(typeof(List.Handler));

如果我想在调用 AddAutoMapper 之前在 MapperConfiguration 上调用 CompileMappings*( 怎么办?
V
Venkat pv

services.AddAutoMapper();对我不起作用。 (我使用的是 Asp.Net Core 2.0)

如下配置后

   var config = new AutoMapper.MapperConfiguration(cfg =>
   {                 
       cfg.CreateMap<ClientCustomer, Models.Customer>();
   });

初始化映射器 IMapper mapper = config.CreateMapper();

并将映射器对象作为单例添加到服务中 services.AddSingleton(mapper);

这样我就可以将 DI 添加到控制器

  private IMapper autoMapper = null;

  public VerifyController(IMapper mapper)
  {              
   autoMapper = mapper;  
  }

我在我的行动方法中使用如下

  ClientCustomer customerObj = autoMapper.Map<ClientCustomer>(customer);

嗨@venkat,您可能只需要将 AutoMapper.Extensions.Microsoft.DependancyInjection 包添加到您的项目中
L
LandSharks

添加到 Arve Systad 提到的测试内容。如果出于某种原因您像我一样想要维护 theutz 解决方案中提供的继承结构,您可以像这样设置 MapperConfiguration:

var mappingProfile = new MappingProfile();
var config = new MapperConfiguration(cfg =>
{
    cfg.AddProfile(mappingProfile);
});
var mapper = new Mapper(config);

我在 NUnit 中做到了这一点。


y
yaronmil

关于 theutz answer ,无需在控制器构造函数中指定 IMapper 映射器参数。

您可以使用 Mapper,因为它是代码任何位置的静态成员。

public class UserController : Controller {
   public someMethod()
   {
      Mapper.Map<User, UserDto>(user);
   }
}

但是静力学有点不可测试,不是吗?
是的。这在许多情况下都有效,但如果在测试中调用此方法时没有配置映射,它将引发异常(因此由于错误的原因导致测试失败)。使用注入的 IMapper,您可以模拟它,例如,如果它与给定的测试无关,则让它返回 null。