AutoMapper 可以很方便完成数据对象之间的转换。
Dto -> Entity
Entity -> ViewModel
Step 1:通过 NuGet 安装 AutoMapper 的包。
<Project Sdk="Microsoft.NET.Sdk.Web"> <PropertyGroup> <TargetFramework>netcoreapp3.1</TargetFramework> </PropertyGroup> <ItemGroup> <PackageReference Include="AutoMapper" Version="9.0.0" /> <PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="7.0.0" /> </ItemGroup> </Project>
准备两个类 User 和 Department
public class User { public int Id { get; set; } public string Name { get; set; } public int Age { get; set; } public string Remark { get; set; } public int DepartmentId { get; set; } public Department DepartmentInfo { get; set; } }
public class Department { public int Id { get; set; } public string Name { get; set; } public string Remark { get; set; } }
创建 User 的 Dto 和 ViewModel
public class UserDto { public int Id { get; set; } public string Name { get; set; } }
public class UserViewModel { public int Id { get; set; } public string Name { get; set; } public int Age { get; set; } public string Remark { get; set; } public int DepartmentId { get; set; } public string DepartmentName { get; set; } }
Step 2:配置好对象之间的转换。
创建类 UserMapper 继承抽象类 Profile
public class UserMapper : Profile { public UserMapper() { CreateMap<UserDto, User>(); CreateMap<User, UserViewModel>() .BeforeMap((u, v) => u.Remark = "Good") .ForMember(v => v.DepartmentId, u => u.MapFrom(user => user.DepartmentId)) .ForMember(v => v.DepartmentName, u => u.MapFrom(user => user.DepartmentInfo.Name)) .AfterMap((u, v) => u.Age++); } }
Profile 里面实现了两个接口
Step 3:注册服务
在 Startup.cs 的 ConfigureServices 方法中注册。
public void ConfigureServices(IServiceCollection services) { // ... services.AddAutoMapper(typeof(UserMapper)); // ... }
Step 4:使用
创建 api 控制器
声明 private readonly IMapper _mapper;
[Route("api/[controller]/[action]")] [ApiController] public class UserController : ControllerBase { private readonly IMapper _mapper; public UserController(IMapper mapper) { _mapper = mapper; } [ActionName("dto")] [HttpGet] public IActionResult DtoToEntity() { var userDto = new UserDto() { Id = 1, Name = "Bill" }; var userEntity = _mapper.Map<UserDto, User>(userDto); JsonResult result = new JsonResult(userEntity); return result; } [ActionName("vo")] [HttpGet] public IActionResult EntityToViewModel() { var department = new Department() { Id = 101, Name = "Market" }; var user = new User() { Id = 1, Name = "Bill", Age = 25, DepartmentId = 101, DepartmentInfo = department }; var viewModel = _mapper.Map<User, UserViewModel>(user); JsonResult result = new JsonResult(viewModel); return result; } }
结果:
Dto -> Entity
Entity -> ViewModel
Step 5:自动化注册
如果每添加一个 Mapper 都需要修改 StartUp 类来完成注册,不是什么好方式。
自动化注册才是更好的(主要还是方便摸鱼)。
为了实现自动化注册,需要找到项目中的所有 Mapper 对象,要给 Mapper 打上一个标记。
添加接口类 IProfile
public interface IProfile { }
在所有的 Mapper 类里面,实现这个接口。
public class UserMapper : Profile, IProfile { public UserMapper() { CreateMap<UserDto, User>(); CreateMap<User, UserViewModel>() .BeforeMap((u, v) => u.Remark = "Good") .ForMember(v => v.DepartmentId, u => u.MapFrom(user => user.DepartmentId)) .ForMember(v => v.DepartmentName, u => u.MapFrom(user => user.DepartmentInfo.Name)) .AfterMap((u, v) => u.Age++); } }
再通过查找所有实现了 IProfile 接口的类,就可以找到所有的 Mapper 对象。
( Profile 是 AutoMapper 组件里的接口,必须自定义项目中的唯一标记。)
创建 MapperRegister 类,实现获取所有的 Mapper 对象。
public class MapperRegister { /// <summary> /// 通过反射自动化注册 /// </summary> /// <returns></returns> public static Type[] MapType() { Assembly ass = Assembly.GetAssembly(typeof(IProfile)); Type[] types = ass.GetTypes(); List<Type> allList = new List<Type>(); foreach (Type item in types) { if (item.IsInterface) continue;//判断是否是接口 Type[] ins = item.GetInterfaces(); foreach (Type ty in ins) { if (ty == typeof(IProfile)) { allList.Add(item); } } } Type[] alltypes = allList.ToArray(); return alltypes; } }
修改 StrartUp 类,调整注册方式。
public void ConfigureServices(IServiceCollection services) { services.AddControllers(); //services.AddAutoMapper(typeof(UserMapper)); //自动化注册 services.AddAutoMapper(MapperRegister.MapType()); }
这样就可以每次添加 Mapper 类的时候,只需要添加 IProfile 标记,就可以自动注册了。
自动化注册方式二:
在很多常见的项目中,同一个项目的Mapper文件都是放在同一个文件夹内。命名都以 Mapper 结尾。
然后在 Startup.cs 里面
services.AddAutoMapper( Assembly.Load("Leaf.Application").GetTypes() .Where(t => t.FullName.EndsWith("Mapper")) .ToArray() );