在 ASP.NET Core 開發中,我們經常需要在不同層之間傳遞數據:比如從數據庫模型(Entity)轉換到 DTO,再從 DTO 轉換為前端視圖模型。這些轉換代碼大量重復、冗長、容易出錯。為了解決這個問題,AutoMapper 誕生了。
本文主要介紹在WebApi(.net?8)環境中使用AutoMapper 14.0.0
官方文檔地址:AutoMapper — AutoMapper documentation
一、什么是 AutoMapper?
AutoMapper 是一個 .NET 類庫,它能自動在兩個類型之間做映射,尤其是當這些類型擁有相似屬性時。它減少了手動編寫 obj.Prop = dto.Prop
的重復性勞動。
public class Student
{public string Name { get; set; }public int Age { get; set; }public string Address{ get; set; }public string Nickname{ get; set; }
}public class Dto_Student
{public string Name { get; set; }public int Age { get; set; }
}
可以直接通過 AutoMapper 在這兩者之間做轉換,而無需顯式賦值。
二、基本用法:從零開始配置
1.安裝 NuGet 包
dotnet add package AutoMapper --version 14.0.0
13.0開始無需引入AutoMapper.Extensions.Microsoft.DependencyInjection?
2.配置映射關系
創建一個映射配置 Profile 類:
public class StudentProfile : Profile
{public StudentProfile(){CreateMap<Student, Dto_Student>();CreateMap<Dto_Student, Student>();}
}
3.在 Program.cs中注冊
using AutoMapper;namespace AutoMapperProfileConfig
{/// <summary>/// 標記程序集啞類/// </summary>public class AutoMapperProfileConfigMarker : Profile{public AutoMapperProfileConfigMarker(){}}
}
builder.Services.AddAutoMapper(typeof(AutoMapperProfileConfigMarker).Assembly);
?
建議專門建立一個類庫,同時為每個表的映射創建一個映射類,然后創建一個專門標記程序集而不做其他事的一個啞類.
這樣可以自動掃描該類庫里面的所有的Profile類(還有幾種其他方法,可自行查看)
4.依賴注入使用映射服務
[ApiController]
[Route("api/[controller]")]
public class StudentController : ControllerBase
{private readonly YourDbContext _context;private readonly IMapper _mapper;public StudentController(YourDbContext context, IMapper mapper){_context = context;_mapper = mapper;}// GET: api/Student[HttpGet]public async Task<ActionResult<IEnumerable<Dto_Student>>> GetStudents(){// 從數據庫獲取 Student 實體列表var students = await _context.Students.ToListAsync();// 使用 AutoMapper 將實體列表映射為 DTO 列表var studentDtos = _mapper.Map<List<Dto_Student>>(students);// 返回給前端return Ok(studentDtos);}
}
5.命名約定?
默認情況映射的屬性名必須完全一致,但你可以配置實現特殊的映射關系.
AutoMapper 中命名約定的優先級關系如下:
? ? ?優先級從高到低:
-
CreateMap().ForMember()
明確指定字段映射 -
在
Profile
中設置的命名約定 -
全局設置(MapperConfiguration 中配置)
-
默認行為(ExactMatchNamingConvention)
public class Source
{public string user_id { get; set; }
}public class Destination
{public string UserId { get; set; }
}
?
情況 1:使用 .ForMember()
明確映射
CreateMap<Source, Destination>().ForMember(dest => dest.UserId, opt => opt.MapFrom(src => src.user_id));
優先級最高,無論有沒有配置命名約定,它都生效
情況 2:Profile 中設置命名約定
public class MyProfile : Profile
{public MyProfile(){SourceMemberNamingConvention = LowerUnderscoreNamingConvention.Instance;DestinationMemberNamingConvention = PascalCaseNamingConvention.Instance;CreateMap<Source, Destination>();}
}
會生效,但僅限于此 Profile
中的 CreateMap
映射。?
情況 3:全局配置命名約定
services.AddAutoMapper(cfg =>
{cfg.SourceMemberNamingConvention = LowerUnderscoreNamingConvention.Instance;cfg.DestinationMemberNamingConvention = PascalCaseNamingConvention.Instance;
}, typeof(SomeMarker));
會自動應用到所有未手動指定命名規則的 Profile 中的映射
情況 4:都不配置時,默認使用 ExactMatch
即只匹配名字完全一致(區分大小寫)的屬性名
設置方式 | 作用范圍 | 優先級 | 備注 |
---|---|---|---|
.ForMember() | 某個字段映射 | 🥇 最高 | 覆蓋一切 |
Profile 中命名約定 | 當前 Profile | 🥈 中高 | 優于全局配置 |
cfg.SourceMemberNamingConvention | 所有 Profile | 🥉 中等 | 默認使用 |
不設置 | 使用 ExactMatch | 最低 | 僅匹配完全相同 |