Permalink
231 lines (180 sloc) 6.31 KB

Configuration

Create a MapperConfiguration instance and initialize configuration via the constructor:

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

The MapperConfiguration instance can be stored statically, in a static field or in a dependency injection container. Once created it cannot be changed/modified.

Alternatively, you can use the static Mapper instance to initialize AutoMapper:

Mapper.Initialize(cfg => {
    cfg.CreateMap<Foo, Bar>();
    cfg.AddProfile<FooProfile>();
});

Profile Instances

A good way to organize your mapping configurations is with profiles. Create classes that inherit from Profile and put the configuration in the constructor:

// 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>();
//     }
// }

In earlier versions the Configure method was used instead of a constructor. As of version 5, Configure() is obsolete. It will be removed in 6.0.

Configuration inside a profile only applies to maps inside the profile. Configuration applied to the root configuration applies to all maps created.

Assembly Scanning for auto configuration

Profiles can be added to the main mapper configuration in a number of ways, either directly:

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.AddProfiles(myAssembly);
});
// ... or static approach:
Mapper.Initialize(cfg => cfg.AddProfiles(myAssembly));

// Can also use assembly names:
Mapper.Initialize(cfg =>
    cfg.AddProfiles(new [] {
        "Foo.UI",
        "Foo.Core"
    });
);

// Or marker types for assemblies:
Mapper.Initialize(cfg =>
    cfg.AddProfiles(new [] {
        typeof(HomeController),
        typeof(Entity)
    });
);

AutoMapper will scan the designated assemblies for classes inheriting from Profile and add them to the configuration.

Naming Conventions

You can set the source and destination naming conventions

Mapper.Initialize(cfg => {
  cfg.SourceMemberNamingConvention = new LowerUnderscoreNamingConvention();
  cfg.DestinationMemberNamingConvention = new PascalCaseNamingConvention();
});

This will map the following properties to each other: property_name -> PropertyName

You can also set this at a per profile level

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

Replacing characters

You can also replace individual characters or entire words in source members during member name matching:

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:

Mapper.Initialize(c =>
{
    c.ReplaceMemberName("Ä", "A");
    c.ReplaceMemberName("í", "i");
    c.ReplaceMemberName("Airlina", "Airline");
});

Recognizing pre/postfixes

Sometimes your source/destination properties will have common pre/postfixes that cause you to have to do a bunch of custom member mappings because the names don't match up. To address this, you can recognize 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; }
}
Mapper.Initialize(cfg => {
    cfg.RecognizePrefixes("frm");
    cfg.CreateMap<Source, Dest>();
});
Mapper.AssertConfigurationIsValid();

By default AutoMapper recognizes the prefix "Get", if you need to clear the prefix:

Mapper.Initialize(cfg => {
    cfg.ClearPrefixes();
    cfg.RecognizePrefixes("tmp");
});

Global property/field filtering

By default, AutoMapper tries to map every public property/field. You can filter out properties/fields with the property/field filters:

Mapper.Initialize(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

By default, AutoMapper only recognizes public members. It can map to private setters, but will skip internal/private methods and properties if the entire property is private/internal. To instruct AutoMapper to recognize members with other visibilities, override the default filters ShouldMapField and/or ShouldMapProperty :

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

Map configurations will now recognize internal/private members.

Configuration compilation

Because expression compilation can be a bit resource intensive, AutoMapper lazily compiles the type map plans on first map. However, this behavior is not always desirable, so you can tell AutoMapper to compile its mappings directly:

Mapper.Initialize(cfg => {});
Mapper.Configuration.CompileMappings();

For a few hundred mappings, this may take a couple of seconds.

Resetting static mapping configuration

The static Mapper.Initialize is intended to be called only once. To reset the static mapping configuration (for example, at the start of tests):

Mapper.Reset();

Mapper.Initialize(cfg => { /* configure again */ });

Reset should not be used in production code. It is intended to support testing scenarios only.