AutoMapper Documentation

repository·main·Indexed 27 days ago

https://github.com/luckypennysoftware/automapper

A library for automating data mapping between different object types to reduce boilerplate code. Includes guides on configuration via MapperConfiguration or IServiceCollection, executing mappings with Map(), and detailed upgrade paths for versions 10.0 through 15.0, covering changes to .NET target frameworks, dependency injection, and licensing requirements.

Tokens
27.8K
Snippets
91
Records
149
Agent score
94%

What's inside AutoMapper

  1. Overview of AutoMapper

    main
    AutoMapper is a convention-based object-to-object mapper designed for model projection. It uses a fluent configuration API and a convention-based matching algorithm to map source values to destination values. It is primarily used to flatten complex object models into DTOs (Data Transfer Objects) or other simple objects suitable for serialization, messaging, or acting as an anti-corruption layer between domain and application layers.
  2. Migrate ConstructProjectionUsing to ConstructUsing

    main

    The ConstructProjectionUsing method has been consolidated into ConstructUsing. The ConstructUsing method now accepts an Expression<Func<TSource, TDestination>> to handle both in-memory mapping and LINQ projections.

    Migration Steps:

    • Replace all usages of ConstructProjectionUsing with ConstructUsing.
    • If your existing ConstructUsing uses lambda statements, method groups, or delegates, you must either:
      • Convert the logic to a lambda expression.
      • Move to the Func-based overloads (ensure you add necessary parameters to your delegates).
    // Old
    IMappingExpression<TSource, TDestination> ConstructUsing(Func<TSource, TDestination> ctor);
    IMappingExpression<TSource, TDestination> ConstructProjectionUsing(Expression<Func<TSource, TDestination>> ctorExpression);
    
    // New
    IMappingExpression<TSource, TDestination> ConstructUsing(Expression<Func<TSource, TDestination>> ctor);
    IMappingExpression<TSource, TDestination> ConstructUsing(Func<TSource, ResolutionContext, TDestination> ctor);
  3. Gather configuration before initialization

    main

    You can decouple the definition of your mapping rules from the initialization of the MapperConfiguration. Use MapperConfigurationExpression to collect your CreateMap and AddProfile calls, which can then be passed to a bootstrapper or used to instantiate the final MapperConfiguration.

    var cfg = new MapperConfigurationExpression();
    cfg.CreateMap<Source, Dest>();
    cfg.AddProfile<MyProfile>();
    MyBootstrapper.InitAutoMapper(cfg);
    
    var mapperConfig = new MapperConfiguration(cfg, loggerFactory);
    IMapper mapper = new Mapper(mapperConfig);
  4. Organize mappings using Profile instances

    main

    To organize mapping configurations, create classes that inherit from Profile. Define your mappings within the class constructor.

    Note: As of version 5.0, the Configure() method is obsolete and will be removed in version 6.0. Use the constructor instead.

    Configuration applied inside a profile only affects maps within that profile, whereas configuration applied to the root MapperConfiguration applies to all maps.

    public class OrganizationProfile : Profile
    {
    	public OrganizationProfile()
    	{
    		CreateMap<Foo, FooDto>();
    		// Use CreateMap... Etc.. here (Profile methods are the same as configuration methods)
    	}
    }
  5. Use Dependency Injection with Destination Factories

    main

    Destination factories are resolved from the DI container, allowing you to inject services into the factory's constructor. To use this, register your services and the factory in the DI container, then use .ConstructUsing<TFactory>() in your AutoMapper configuration.

    public class DIAwareConstructor : IDestinationFactory<Source, Destination>
    {
        private readonly IMyService _service;
    
        public DIAwareConstructor(IMyService service)
        {
            _service = service;
        }
    
        public Destination Construct(Source source, ResolutionContext context)
        {
            return new Destination 
            { 
                InitialValue = _service.CalculateValue(source.Value) 
            };
        }
    }
    
    // Registration
    services.AddScoped<IMyService, MyService>();
    services.AddAutoMapper(cfg =>
    {
        cfg.CreateMap<Source, Destination>()
            .ConstructUsing<DIAwareConstructor>();
    }, typeof(IMyService).Assembly);
  6. Create open generic type maps

    main

    AutoMapper allows you to define a single mapping for open generic types. Because C# requires closed generic type parameters, you must use the System.Type overload of CreateMap to define the mapping for the open generic types (e.g., typeof(Source<>)). Once defined, AutoMapper will automatically apply this configuration to any closed generic types (e.g., Source<int> to Destination<int>) at runtime.

    Note: AutoMapper skips open generic type maps during configuration validation to avoid errors on incompatible closed types (like Source<Foo> to Destination<Bar>) that do not have a valid conversion.

    public class Source<T> {
        public T Value { get; set; }
    }
    
    public class Destination<T> {
        public T Value { get; set; }
    }
    
    // Create the mapping using System.Type
    var configuration = new MapperConfiguration(cfg => cfg.CreateMap(typeof(Source<>), typeof(Destination<>)), loggerFactory);
    
    // Usage with closed types
    var source = new Source<int> { Value = 10 };
    var dest = mapper.Map<Source<int>, Destination<int>>(source);