1.什麼是AutoMapper? AutoMapper是一個對象-對象映射器。對象-對象映射通過將一種類型的輸入對象轉換為另一種類型的輸出對象來工作。使AutoMapper變得有趣的是,它提供了一些有趣的約定,免去用戶不需要瞭解如何將類型A映射為類型B。只要類型B遵循AutoMapper既定的約定, ...
1.什麼是AutoMapper?
AutoMapper是一個對象-對象映射器。對象-對象映射通過將一種類型的輸入對象轉換為另一種類型的輸出對象來工作。使AutoMapper變得有趣的是,它提供了一些有趣的約定,免去用戶不需要瞭解如何將類型A映射為類型B。只要類型B遵循AutoMapper既定的約定,就需要幾乎零配置來映射兩個類型。映射代碼雖然比較無聊,但是AutoMapper為我們提供簡單的類型配置以及簡單的映射測試,而映射可以在應用程式中的許多地方發生,但主要發生在層之間的邊界中,比如,UI /域層之間或服務/域層之間。一層的關註點通常與另一層的關註點衝突,因此對象-對象映射導致分離的模型,其中每一層的關註點僅會影響該層中的類型。
2.如何在Core上面使用AutoMapper組件?
先在Startup.ConfigureServices註入AutoMapper組件服務,然後在Startup.Configure上獲取AutoMapper服務配置擴展類創建對象-對象映射關係,為了好統一管理代碼,可以新建一個AutoMapperExtension靜態類,把以下代碼封裝一下:
public static class AutoMapperExtension { /// <summary> /// 新增自動映射服務 /// </summary> /// <param name="service"></param> /// <returns></returns> public static IServiceCollection AddAutoMapper(this IServiceCollection services) { #region 方案一 //註冊AutoMapper配置擴展類服務 services.TryAddSingleton<MapperConfigurationExpression>(); //註冊AutoMapper配置擴展類到AutoMapper配置服務去 services.TryAddSingleton(serviceProvider => { var mapperConfigurationExpression = serviceProvider.GetRequiredService<MapperConfigurationExpression>(); var mapperConfiguration = new MapperConfiguration(mapperConfigurationExpression); mapperConfiguration.AssertConfigurationIsValid(); return mapperConfiguration; }); //註入IMapper介面DI服務 services.TryAddSingleton(serviceProvider => { var mapperConfiguration = serviceProvider.GetRequiredService<MapperConfiguration>(); return mapperConfiguration.CreateMapper(); }); return services; #endregion } /// <summary> /// 使用自動映射配置擴展類 /// </summary> /// <param name="applicationBuilder"></param> /// <returns></returns> public static IMapperConfigurationExpression UseAutoMapper(this IApplicationBuilder applicationBuilder) { //獲取已註冊服務AutoMapper配置擴展類 return applicationBuilder.ApplicationServices.GetRequiredService<MapperConfigurationExpression>(); } } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { ...... //添加自動映射組件DI服務 services.AddAutoMapper(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env) { ...... //註冊組件之後,創建映射對象 var expression = app.UseAutoMapper(); expression.CreateMap<Customer, CustomerDto>(); expression.CreateMap<Address, AddressDto>(); }
因為IMapper介面已經在ConfigureServices方法註入DI服務了,所以無需再重新註入,只需要直接使用IMapper調用其方法就可以:
public class BlogsController : Controller { private IMapper _iMapper { get; } public BlogsController(IMapper iMapper) { _iMapper = iMapper; } // GET: Blogs public async Task<IActionResult> Index() { //對象-對象數據傳輸 var dto = _iMapper.Map<CustomerDto>(CustomerInitialize()); ...... } //手動賦值客戶對象數據 private Customer CustomerInitialize() { var _customer = new Customer() { Id = 1, Name = "Eduardo Najera", Credit = 234.7m, Address = new Address() { City = "istanbul", Country = "turkey", Id = 1, Street = "istiklal cad." }, HomeAddress = new Address() { City = "istanbul", Country = "turkey", Id = 2, Street = "istiklal cad." }, WorkAddresses = new List<Address>() { new Address() {City = "istanbul", Country = "turkey", Id = 5, Street = "istiklal cad."}, new Address() {City = "izmir", Country = "turkey", Id = 6, Street = "konak"} }, Addresses = new List<Address>() { new Address() {City = "istanbul", Country = "turkey", Id = 3, Street = "istiklal cad."}, new Address() {City = "izmir", Country = "turkey", Id = 4, Street = "konak"} }.ToArray() }; return _customer; } }
運行效果:
3.如果更加靈活使用AutoMapper組件?
相信在第二章節時候,相信大家都會發現一個問題,如果生產場景業務越來越龐大,需創建對應業務對象也會越來越多,如果面對這樣的業務場景難道要在Configure方法裡面創建越來越多的映射關係嗎?例:
var expression = app.UseAutoMapper(); expression.CreateMap<A, ADto>(); expression.CreateMap<B, BDto>(); expression.CreateMap<C, CDto>(); expression.CreateMap<D, DDto>(); ......
很顯然這樣子是不可行的,這樣會導致後續代碼越來越多,難以維護。那麼現在讓我們來解決這個問題。首先新建一個自動註入屬性的AutoInjectAttribute密封類,具體代碼如下:
public sealed class AutoInjectAttribute : Attribute { public Type SourceType { get; } public Type TargetType { get; } public AutoInjectAttribute(Type sourceType, Type targetType) { SourceType = sourceType; TargetType = targetType; } }
新增這個AutoInjectAttribute密封類,目的是聲明每個DTO對象(數據傳輸對象)與對應數據源對象是傳輸關係,方便在Configure裡面自動註冊創建映射關係,例:
//聲明源對象,目標對象 [AutoInject(sourceType: typeof(Customer),targetType:typeof(CustomerDto))] public class CustomerDto { public int Id { get; set; } public string Name { get; set; } public Address Address { get; set; } public AddressDto HomeAddress { get; set; } public AddressDto[] Addresses { get; set; } public List<AddressDto> WorkAddresses { get; set; } public string AddressCity { get; set; } }
然後創建一個自動註入AutoInjectFactory工廠類,檢測運行中的程式集是否有AutoInjectAttribute屬性聲明,如果有則插入一個類型數據集中返回,目的是把所有聲明需要映射DTO對象跟數據源對象自動創建映射關係:
public class AutoInjectFactory { public List<(Type, Type)> AddAssemblys { get { var assemblys =new List<Assembly>() { Assembly.GetExecutingAssembly() }; List<(Type, Type)> ConvertList = new List<(Type, Type)>(); foreach (var assembly in assemblys) { var atributes = assembly.GetTypes() .Where(_type => _type.GetCustomAttribute<AutoInjectAttribute>() != null) .Select(_type => _type.GetCustomAttribute<AutoInjectAttribute>()); foreach (var atribute in atributes) { ConvertList.Add((atribute.SourceType, atribute.TargetType)); } } return ConvertList; } } }
在第2小節AutoMapperExtension靜態類的AddAutoMapper方法內修改如下代碼:
#region 方案二 //註入AutoMapper配置擴展類服務 services.TryAddSingleton<MapperConfigurationExpression>(); //註入自動註入工廠類服務 services.TryAddSingleton<AutoInjectFactory>(); //註入AutoMapper配置擴展類到AutoMapper配置服務去 services.TryAddSingleton(serviceProvider => { var mapperConfigurationExpression = serviceProvider.GetRequiredService<MapperConfigurationExpression>(); //通過自動註入工廠類獲取聲明數據源對象與DTO對象自動創建映射關係 var factory = serviceProvider.GetRequiredService<AutoInjectFactory>(); foreach (var (sourceType, targetType) in factory.AddAssemblys) { mapperConfigurationExpression.CreateMap(sourceType, targetType); } var mapperConfiguration = new MapperConfiguration(mapperConfigurationExpression); mapperConfiguration.AssertConfigurationIsValid(); return mapperConfiguration; }); //註入IMapper介面DI服務 services.TryAddSingleton(serviceProvider => { var mapperConfiguration = serviceProvider.GetRequiredService<MapperConfiguration>(); return mapperConfiguration.CreateMapper(); }); return services; #endregion
再新增一個使用自動註入工廠類服務靜態方法:
/// <summary> /// 使用自動註入工廠類 /// </summary> /// <param name="applicationBuilder"></param> public static void UseAutoInject(this IApplicationBuilder applicationBuilder) { applicationBuilder.ApplicationServices.GetRequiredService<AutoInjectFactory>(); }
然後在Startup.ConfigureServices註入AutoMapper組件服務,然後在Startup.Configure上調用UseAutoInject靜態方法,具體代碼如下:
app.UseAutoInject();
運行效果:
從運行結果來看依然是這個酸爽!
參考文獻:
AutoMapper