AutoMapper 10.0使用教程

什麼是AutoMapper

咱們都知道,引用類型直接賦值傳遞的是地址,若是直接賦值,則改變一個類的屬性的同時也在改變另外一個類。web

因此,當咱們須要實現像int類型直接賦值更改互不影響的效果時,咱們須要映射微信

將A類映射賦值到B類的時候,咱們就須要一個對象映射器(object-object),也就是AutoMapper。app

咱們只須要提早配置好要映射的兩個類,便可輕鬆實現反射。ide

配置

使用MapperConfiguration配置

建立一個 MapperConfiguration 實例並經過構造函數初始化配置:svg

var config = new MapperConfiguration(cfg => {
    cfg.CreateMap<Foo, Bar>();
    cfg.AddProfile<FooProfile>();
});

MapperConfiguration 實例能夠靜態存儲,也能夠存儲在靜態字段或依賴注入容器中。一旦建立,它就不能被更改/修改。函數

var configuration = new MapperConfiguration(cfg => {
    cfg.CreateMap<Foo, Bar>();
    cfg.AddProfile<FooProfile>();
});

注:從9.0開始,靜態 API 再也不可用。post

使用Profile Instances配置

組織映射配置的一個好方法是使用配置文件。建立從 Profile 繼承的類,並將配置放入構造函數中:網站

// This is the approach starting with version 5
public class OrganizationProfile : Profile
{
	public OrganizationProfile()
	{
		CreateMap<Foo, FooDto>();
		// Use CreateMap... Etc.. here (Profile methods are the same as configuration methods)
	}
}

// How it was done in 4.x - as of 5.0 this is obsolete:
// public class OrganizationProfile : Profile
// {
// protected override void Configure()
// {
// CreateMap<Foo, FooDto>();
// }
// }

在早期版本中,使用 Configure 方法而不是構造函數。從版本5開始,Configure ()就過期了。它將在6.0版本中被刪除。this

配置文件中的配置只應用於配置文件中的映射。應用於根配置的配置應用於建立的全部映射。spa

Assembly Scanning for auto configuration (自動配置程序集掃描)

配置文件能夠經過多種方式直接添加到主映射器配置中:

cfg.AddProfile<OrganizationProfile>();
cfg.AddProfile(new OrganizationProfile());
or by automatically scanning for profiles:

或者經過自動掃描檔案:

// Scan for all profiles in an assembly
// ... using instance approach:
var config = new MapperConfiguration(cfg => {
    cfg.AddMaps(myAssembly);
});
var configuration = new MapperConfiguration(cfg => cfg.AddMaps(myAssembly));

// Can also use assembly names:
var configuration = new MapperConfiguration(cfg =>
    cfg.AddMaps(new [] {
        "Foo.UI",
        "Foo.Core"
    });
);

// Or marker types for assemblies:
var configuration = new MapperConfiguration(cfg =>
    cfg.AddMaps(new [] {
        typeof(HomeController),
        typeof(Entity)
    });
);

AutoMapper 將掃描指定的程序集,從 Profile 繼承類,並將它們添加到配置中。

Naming Conventions(命名約定)

您能夠設置源和目標命名約定

var configuration = new MapperConfiguration(cfg => {
  cfg.SourceMemberNamingConvention = new LowerUnderscoreNamingConvention();
  cfg.DestinationMemberNamingConvention = new PascalCaseNamingConvention();
});

這將把如下屬性映射到彼此: property _ name-> PropertyName

您還能夠將其設置爲每一個配置文件級別

public class OrganizationProfile : Profile
{
  public OrganizationProfile()
  {
    SourceMemberNamingConvention = new LowerUnderscoreNamingConvention();
    DestinationMemberNamingConvention = new PascalCaseNamingConvention();
    //Put your CreateMap... Etc.. here
  }
}

若是你不須要變數命名原則,你可使用精確匹配命名協議。

Replacing characters (替換字符)

還能夠在成員名稱匹配過程當中替換源成員中的單個字符或整個單詞:

public class Source
{
    public int Value { get; set; }
    public int Ävíator { get; set; }
    public int SubAirlinaFlight { get; set; }
}
public class Destination
{
    public int Value { get; set; }
    public int Aviator { get; set; }
    public int SubAirlineFlight { get; set; }
}

We want to replace the individual characters, and perhaps translate a word:

咱們想要替換單個字符,或許能夠翻譯一個單詞:

var configuration = new MapperConfiguration(c =>
{
    c.ReplaceMemberName("Ä", "A");
    c.ReplaceMemberName("í", "i");
    c.ReplaceMemberName("Airlina", "Airline");
});

Recognizing pre/postfixes 識別前/後綴

有時候,源/目標屬性會有共同的前/後綴,這致使您必須執行一系列自定義成員映射,由於名稱不匹配。爲了解決這個問題,您能夠識別前/後綴:

public class Source {
    public int frmValue { get; set; }
    public int frmValue2 { get; set; }
}
public class Dest {
    public int Value { get; set; }
    public int Value2 { get; set; }
}
var configuration = new MapperConfiguration(cfg => {
    cfg.RecognizePrefixes("frm");
    cfg.CreateMap<Source, Dest>();
});

默認狀況下,AutoMapper 識別前綴「 Get」 ,若是您須要清除前綴:

var configuration = new MapperConfiguration(cfg => {
    cfg.ClearPrefixes();
    cfg.RecognizePrefixes("tmp");
});

Global property/field filtering 全局屬性/字段篩選

默認狀況下,AutoMapper 會嘗試映射每一個公共屬性/字段。您可使用屬性/字段過濾器過濾出屬性/字段:

var configuration = new MapperConfiguration(cfg =>
{
	// don't map any fields
	cfg.ShouldMapField = fi => false;

	// map properties with a public or private getter
	cfg.ShouldMapProperty = pi =>
		pi.GetMethod != null && (pi.GetMethod.IsPublic || pi.GetMethod.IsPrivate);
});
Configuring

Visibility 配置可見性

默認狀況下,AutoMapper 只能識別公共成員。它能夠映射到私有 setters,可是若是整個屬性都是 private/internal,則會跳過 internal/private 方法和屬性。要指示 AutoMapper 識別具備其餘可視性的成員,請覆蓋默認過濾器 ShouldMapField 和/或 shouldmapproty:

var configuration = new MapperConfiguration(cfg =>
{
    // map properties with public or internal getters
    cfg.ShouldMapProperty = p => p.GetMethod.IsPublic || p.GetMethod.IsAssembly;
    cfg.CreateMap<Source, Destination>();
});

Configuration compilation 配置編譯

因爲表達式編譯可能佔用位資源,所以 AutoMapper 在第一個映射上編譯類型映射計劃。然而,這種行爲並不老是可取的,因此你能夠告訴 AutoMapper 直接編譯它的映射:

var configuration = new MapperConfiguration(cfg => {});
configuration.CompileMappings();

對於幾百個映射,這可能須要幾秒鐘。

Dependency Injection (依賴注入)

AutoMapper 支持使用靜態服務位置構建自定義值解析器、自定義類型轉換器和值轉換器:

var configuration = new MapperConfiguration(cfg =>
{
    cfg.ConstructServicesUsing(ObjectFactory.GetInstance);

    cfg.CreateMap<Source, Destination>();
});

或動態服務位置,用於基於實例的容器(包括子/嵌套容器) :

var mapper = new Mapper(configuration, childContainer.GetInstance);

var dest = mapper.Map<Source, Destination>(new Source { Value = 15 });

Queryable Extensions 可查詢擴展

從8.0開始,你可使用 IMapper。ProjectTo.對於舊版本,您須要將配置傳遞給擴展方法 IQueryable。項目組 < t > (圖像提供者)。

注意 IQueryable。ProjectTo是比IMappe更有限 的映射,由於只支持基礎 LINQ 提供程序所容許的內容。這意味着不能像對 Map 那樣對值解析器和轉換器使用 DI。

例子

ASP.NET Core

有一個 NuGet 包將與這裏描述的默認注入機制一塊兒使用,並在這個項目中使用。

您可使用配置文件定義配置。而後你讓 AutoMapper 知道哪些程序集是經過在啓動時調用 IServiceCollection 擴展方法 AddAutoMapper 定義的概要文件:

services.AddAutoMapper(profileAssembly1, profileAssembly2 /*, ...*/);
or marker types:

或者標記類型:

services.AddAutoMapper(typeof(ProfileTypeFromAssembly1), typeof(ProfileTypeFromAssembly2) /*, ...*/);

如今你能夠在運行時將 AutoMapper 注入到你的服務/控制器中:

public class EmployeesController {
	private readonly IMapper _mapper;

	public EmployeesController(IMapper mapper) => _mapper = mapper;

	// use _mapper.Map or _mapper.ProjectTo
}

AutoFac

Autofac for AutoMapper

Ninject

對於那些使用 Ninject 的人來講,這裏是一個用於 AutoMapper 的 Ninject 模塊的例子

public class AutoMapperModule : NinjectModule
{
    public override void Load()
    {
        Bind<IValueResolver<SourceEntity, DestModel, bool>>().To<MyResolver>();

        var mapperConfiguration = CreateConfiguration();
        Bind<MapperConfiguration>().ToConstant(mapperConfiguration).InSingletonScope();

        // This teaches Ninject how to create automapper instances say if for instance
        // MyResolver has a constructor with a parameter that needs to be injected
        Bind<IMapper>().ToMethod(ctx =>
             new Mapper(mapperConfiguration, type => ctx.Kernel.Get(type)));
    }

    private MapperConfiguration CreateConfiguration()
    {
        var config = new MapperConfiguration(cfg =>
        {
            // Add all profiles in current assembly
            cfg.AddMaps(GetType().Assembly);
        });

        return config;
    }
}

Simple Injector 簡單注射器

工做流程以下:

  1. 經過 myregistry.Register 註冊你的類型
  2. MapperProvider 容許您直接將 IMapper 實例注入到其餘類中
  3. 使用 propertythatdependensoniovalueresolver 解析一個值
  4. 將 IService 注入到 propertythatdependensoniovalueresolver 中,而後就可使用了

ValueResolver 能夠訪問 IService,由於咱們經過 MapperConfigurationExpression. ConstructServicesUsing 註冊容器

public class MyRegistrar
{
    public void Register(Container container)
    {
        // Injectable service
        container.RegisterSingleton<IService, SomeService>();

        // Automapper
        container.RegisterSingleton(() => GetMapper(container));
    }

    private AutoMapper.IMapper GetMapper(Container container)
    {
        var mp = container.GetInstance<MapperProvider>();
        return mp.GetMapper();
    }
}

public class MapperProvider
{
    private readonly Container _container;

    public MapperProvider(Container container)
    {
        _container = container;
    }

    public IMapper GetMapper()
    {
        var mce = new MapperConfigurationExpression();
        mce.ConstructServicesUsing(_container.GetInstance);

        mce.AddMaps(typeof(SomeProfile).Assembly);

        var mc = new MapperConfiguration(mce);
        mc.AssertConfigurationIsValid();

        IMapper m = new Mapper(mc, t => _container.GetInstance(t));

        return m;
    }
}

public class SomeProfile : Profile
{
    public SomeProfile()
    {
        var map = CreateMap<MySourceType, MyDestinationType>();
        map.ForMember(d => d.PropertyThatDependsOnIoc, opt => opt.MapFrom<PropertyThatDependsOnIocValueResolver>());
    }
}

public class PropertyThatDependsOnIocValueResolver : IValueResolver<MySourceType, object, int>
{
    private readonly IService _service;

    public PropertyThatDependsOnIocValueResolver(IService service)
    {
        _service = service;
    }

    int IValueResolver<MySourceType, object, int>.Resolve(MySourceType source, object destination, int destMember, ResolutionContext context)
    {
        return _service.MyMethod(source);
    }
}

Castle Windsor

對於那些使用Castle Windsor在這裏是一個例子

public class AutoMapperInstaller : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
        {
            // Register all mapper profiles
            container.Register(
                Classes.FromAssemblyInThisApplication(GetType().Assembly)
                .BasedOn<Profile>().WithServiceBase());
                
            // Register IConfigurationProvider with all registered profiles
            container.Register(Component.For<IConfigurationProvider>().UsingFactoryMethod(kernel =>
            {
                return new MapperConfiguration(configuration =>
                {
                    kernel.ResolveAll<Profile>().ToList().ForEach(configuration.AddProfile);
                });
            }).LifestyleSingleton());
            
            // Register IMapper with registered IConfigurationProvider
            container.Register(
                Component.For<IMapper>().UsingFactoryMethod(kernel =>
                    new Mapper(kernel.Resolve<IConfigurationProvider>(), kernel.Resolve)));
        }
}

Catel.IoC

對於那些使用 Catel.IoC 的用戶,下面介紹如何註冊自動控制器。首先使用配置文件定義配置。而後你讓 AutoMapper 知道在哪些程序集中這些配置文件是經過在啓動時在 ServiceLocator 中註冊 AutoMapper 定義的:

配置建立方法:

public static MapperConfiguration CreateConfiguration()
{
    var config = new MapperConfiguration(cfg =>
    {
        // Add all profiles in current assembly
        cfg.AddMaps(GetType().Assembly);
    });

    return config;
}

如今你能夠在運行時將 AutoMapper 注入到你的服務/控制器中:

public class EmployeesController {
	private readonly IMapper _mapper;

	public EmployeesController(IMapper mapper) => _mapper = mapper;

	// use _mapper.Map or _mapper.ProjectTo
}

後記

本人不是大佬,只是道路先行者,在落河後,向後來的人大喊一聲,這裏有坑,不要過來啊!

縱然如此,依舊有人重複着落河,重複着吶喊······

我的博客網站 Blog

技術交流Q羣: 1012481075 羣內有各類流行書籍資料

文章後續會在公衆號更新,微信搜索 OneByOneDotNet 便可關注。

你的一分鼓勵,個人十分動力,點贊免費,感恩回饋。喜歡就點贊評論吧,雙擊6666~

相關文章
相關標籤/搜索