我在.NET方面相对较新,决定学习.NET Core而非传统方式。我发现了一篇详细的文章 在此设置AutoMapper,但是否有更简单的教程适合新手?
我在.NET方面相对较新,决定学习.NET Core而非传统方式。我发现了一篇详细的文章 在此设置AutoMapper,但是否有更简单的教程适合新手?
我找到答案了!以下是详细信息:
通过NuGet将主要的AutoMapper软件包添加到您的解决方案中。
通过NuGet将AutoMapper依赖注入套件添加到您的解决方案中。
为映射配置创建一个新类(我在主解决方案目录中创建了一个名为MappingProfile.cs
的类,并添加了以下代码)。下面以User
和UserDto
对象为例。
public class MappingProfile : Profile {
public MappingProfile() {
// Add as many of these lines as you need to map your objects
CreateMap<User, UserDto>();
CreateMap<UserDto, User>();
}
}
然后将AutoMapperConfiguration添加到Startup.cs
中,如下所示: public void ConfigureServices(IServiceCollection services) {
// .... Ignore code before this
// Auto Mapper Configurations
var mapperConfig = new MapperConfiguration(mc =>
{
mc.AddProfile(new MappingProfile());
});
IMapper mapper = mapperConfig.CreateMapper();
services.AddSingleton(mapper);
services.AddMvc();
}
要在代码中调用映射对象,请执行以下操作: public class UserController : Controller {
// Create a field to store the mapper object
private readonly IMapper _mapper;
// Assign the object in the constructor for dependency injection
public UserController(IMapper mapper) {
_mapper = mapper;
}
public async Task<IActionResult> Edit(string id) {
// Instantiate source object
// (Get it from the database or whatever your code calls for)
var user = await _context.Users
.SingleOrDefaultAsync(u => u.Id == id);
// Instantiate the mapped data transfer object
// using the mapper you stored in the private field.
// The type of the source object is the first type argument
// and the type of the destination is the second.
// Pass the source object you just instantiated above
// as the argument to the _mapper.Map<>() method.
var model = _mapper.Map<UserDto>(user);
// .... Do whatever you want after that!
}
}
使用AutoMapper与ASP.NET Core的步骤。
步骤1. 从NuGet包安装AutoMapper.Extensions.Microsoft.DependencyInjection。
步骤2. 创建一个名为“Mappings”的文件夹以在Solution中保存映射。
步骤3. 添加Mapping文件夹后,我们添加了一个名称为“MappingProfile”的类,这个名称可以是任何独特且易于理解的名称。
在这个类中,我们将维护所有映射。
步骤4. 在Startup“ConfigureServices”中初始化Mapper
在Startup类中,我们需要初始化我们创建的Profile并注册AutoMapper服务。
Mapper.Initialize(cfg => cfg.AddProfile<MappingProfile>());
services.AddAutoMapper();
展示了ConfigureServices方法的代码片段,其中我们需要初始化和注册AutoMapper。
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' 不包含 'initialize' 的定义。
我正在使用 AutoMapper.Extensions.Microsoft.DependencyInjection
版本 7.0.0。 - kimbaudi我希望你能继续完善@theutz的答案 - 特别是这一行:
// services.AddAutoMapper(typeof(Startup)); // <-- newer automapper version uses this signature.
AutoMapper.Extensions.Microsoft.DependencyInjection版本3.2.0存在一个(可能的)错误。(我正在使用.NET Core 2.0)
这个问题在这个GitHub issue中解决。如果你继承AutoMapper的Profile类的类存在于启动类不在的程序集中,那么如果你的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已经JIT编译了包含AutoMapper配置文件的程序集,但这可能是真的也可能不是真的,因为它们只在需要时才被JIT编译(更多详细信息请参见此StackOverflow问题)。
我是这样解决的(与上面类似,但我觉得这是一种更简洁的解决方案)。适用于 .NET Core 3.x
创建MappingProfile.cs类,并填充构造函数与映射(我计划使用一个类来保存所有我的映射)。
public class MappingProfile : Profile
{
public MappingProfile()
{
CreateMap<Source, Dest>().ReverseMap();
}
}
在 Startup.cs 中添加以下内容以添加到 DI(程序集参数是保存映射配置的类,在我的情况下,它是 MappingProfile 类)。
//add automapper DI
services.AddAutoMapper(typeof(MappingProfile));
在控制器中,使用它就像使用其他依赖注入对象一样
[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);
}
}
AutoMapper.Extensions.Microsoft.DependencyInjection
。 - John Jangservices.AddScoped<IMapper,Mapper>();
。IMapper 是 AutoMapper 接口,而 Mapper 则来自 AutoMapper,因此我们不需要做任何事情。 - milostheutz的回答非常好,我只想补充一点:
如果你让你的映射配置从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();
}
我喜欢很多答案,特别是@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());
(更优雅的方法可能是一个不带参数的扩展与这个编码)。
谢谢,Lucian!
在最新版本的asp.net core中,你应该使用以下初始化:
services.AddAutoMapper(typeof(YourMappingProfileClass));
services.AddAutoMapper(Assembly.GetExecutingAssembly());
来获取此程序集中从 Profile 类派生的所有映射类。 - Sayyed Dawood需要安装一个包来设置automapper。
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;
}
}
员工.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; }
}
在我的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) });
? - Second Person Shooter对于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());
在控制器或服务中:
注入 Mapper:
private readonly IMapper _mapper;
使用方法:
var obj = _mapper.Map<TDest>(sourceObject);