### Install AutoMapper via .NET CLI Source: https://github.com/luckypennysoftware/automapper/blob/main/README.md Install the AutoMapper NuGet package using the .NET CLI. ```bash dotnet add package AutoMapper ``` -------------------------------- ### Initialize AutoMapper Instance Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Setup.md Demonstrates the basic setup for creating an AutoMapper instance with a configuration and mapping. ```csharp var config = new MapperConfiguration(cfg => { cfg.AddProfile(); cfg.CreateMap(); }, loggerFactory); var mapper = config.CreateMapper(); // or IMapper mapper = new Mapper(config); var dest = mapper.Map(new Source()); ``` -------------------------------- ### Install AutoMapper via Package Manager Console Source: https://github.com/luckypennysoftware/automapper/blob/main/README.md Install the AutoMapper NuGet package using the Package Manager Console in Visual Studio. ```powershell PM> Install-Package AutoMapper ``` -------------------------------- ### Define Source and Destination Types Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Custom-type-converters.md Example source and destination classes for demonstrating custom type conversion. ```csharp public class Source { public string Value1 { get; set; } public string Value2 { get; set; } public string Value3 { get; set; } } ``` ```csharp public class Destination { public int Value1 { get; set; } public DateTime Value2 { get; set; } public Type Value3 { get; set; } } ``` -------------------------------- ### Configure Custom Type Converters Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Custom-type-converters.md Example of configuring custom type converters for string to int, DateTime, and Type mappings. ```csharp [Test] public void Example() { var configuration = new MapperConfiguration(cfg => { cfg.CreateMap().ConvertUsing(s => Convert.ToInt32(s)); cfg.CreateMap().ConvertUsing(new DateTimeTypeConverter()); cfg.CreateMap().ConvertUsing(); cfg.CreateMap(); }, loggerFactory); configuration.AssertConfigurationIsValid(); var source = new Source { Value1 = "5", Value2 = "01/01/2000", Value3 = "AutoMapperSamples.GlobalTypeConverters.GlobalTypeConverters+Destination" }; Destination result = mapper.Map(source); result.Value3.ShouldEqual(typeof(Destination)); } ``` -------------------------------- ### Define Mapping Profile with Constructor Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Configuration.md Organize mapping configurations by creating classes that inherit from Profile and defining mappings within their constructors. This approach is recommended starting from version 5. ```csharp public class OrganizationProfile : Profile { public OrganizationProfile() { CreateMap(); // Use CreateMap... Etc.. here (Profile methods are the same as configuration methods) } } ``` -------------------------------- ### Custom Resolver Implementation Example Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Custom-value-resolvers.md An example implementation of a custom value resolver that calculates the sum of two source properties. This resolver is specific to Source, Destination, and int types. ```csharp public class CustomResolver : IValueResolver { public int Resolve(Source source, Destination destination, int member, ResolutionContext context) { return source.Value1 + source.Value2; } } ``` -------------------------------- ### Define Entities for Mapping Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Reverse-Mapping-and-Unflattening.md Defines the 'Order' and 'Customer' entities used in mapping examples. These are plain C# classes. ```csharp public class Order { public decimal Total { get; set; } public Customer Customer { get; set; } } public class Customer { public string Name { get; set; } } ``` -------------------------------- ### Configure Constructor Selection Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Construction.md Specify criteria for which constructors AutoMapper should consider for destination object creation. This example uses only public constructors. ```csharp // use only public constructors var configuration = new MapperConfiguration(cfg => cfg.ShouldUseConstructor = constructor => constructor.IsPublic, loggerFactory); ``` -------------------------------- ### Using context.State Instead of context.Items (v13.0+) Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Custom-value-resolvers.md Starting with version 13.0, `context.State` can be used similarly to `context.Items` for passing data during mapping. Note that `State` and `Items` are mutually exclusive per `Map` call. ```csharp cfg.CreateMap() .ForMember(dest => dest.Foo, opt => opt.MapFrom((src, dest, destMember, context) => context.State["Foo"])); ``` -------------------------------- ### Demonstrate Mapping and Unflattening Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Reverse-Mapping-and-Unflattening.md Illustrates the usage of the configured reverse map, showing how to map an 'Order' to 'OrderDto' and then modify the DTO and map it back to update the 'Order' object, including unflattening. ```csharp var customer = new Customer { Name = "Bob" }; var order = new Order { Customer = customer, Total = 15.8m }; var orderDto = mapper.Map(order); orderDto.CustomerName = "Joe"; mapper.Map(orderDto, order); order.Customer.Name.ShouldEqual("Joe"); ``` -------------------------------- ### LINQ Projections with IMapper.ProjectTo Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Setup.md Illustrates how to use IMapper.ProjectTo for LINQ projections within a controller, requiring the MapperConfiguration instance to be passed. ```csharp public class ProductsController : Controller { public ProductsController(MapperConfiguration config) { this.config = config; } private MapperConfiguration config; public ActionResult Index(int id) { var dto = dbContext.Products .Where(p => p.Id == id) .ProjectTo(config) .SingleOrDefault(); return View(dto); } } ``` -------------------------------- ### Initialize MapperConfiguration with Constructor Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Configuration.md Initialize MapperConfiguration using its constructor, passing a lambda for configuration and an optional logger factory. The configuration instance should be stored statically or in a DI container as it cannot be modified after creation. ```csharp var config = new MapperConfiguration(cfg => { cfg.CreateMap(); cfg.AddProfile(); }, loggerFactory); ``` ```csharp var configuration = new MapperConfiguration(cfg => { cfg.CreateMap(); cfg.AddProfile(); }, loggerFactory); ``` -------------------------------- ### Perform Object Mapping Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Getting-started.md Instantiate a mapper using the configuration and then use the Map method to transform a source object into a destination object. Dependency injection is recommended for managing the IMapper instance. ```csharp var mapper = config.CreateMapper(); // or var mapper = new Mapper(config); OrderDto dto = mapper.Map(order); ``` -------------------------------- ### ProjectTo with ToList and Manual Iteration Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Expression-Translation-(UseAsDataSource).md This approach uses ProjectTo and ToList, allowing for manual iteration and modification of the DTOs after they are loaded into memory. ```csharp var configuration = new MapperConfiguration(cfg => cfg.CreateMap() .ForMember(dto => dto.Item, conf => conf.MapFrom(ol => ol.Item.Name)), loggerFactory); public List GetLinesForOrder(int orderId) { using (var context = new orderEntities()) { var dtos = context.OrderLines.Where(ol => ol.OrderId == orderId) .ProjectTo().ToList(); foreach(var dto in dtos) { // edit some property, or load additional data from the database and augment the dtos } return dtos; } } ``` -------------------------------- ### Translate a Collection Filtering and Ordering Expression Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Expression-Translation-(UseAsDataSource).md Translate expressions involving collection operations like `Where` and `OrderBy`. This example demonstrates mapping a queryable expression from `OrderLineDTO` to `OrderLine`. ```csharp Expression,IQueryable>> dtoExpression = dtos => dtos.Where(dto => dto.Quantity > 5).OrderBy(dto => dto.Quantity); var expression = mapper.Map,IQueryable>>(dtoExpression); ``` -------------------------------- ### Configure Mapping Source: https://github.com/luckypennysoftware/automapper/blob/main/ISSUE_TEMPLATE.md Configure your mappings using Mapper.Initialize or CreateMap. This is where you define how source types map to destination types. ```csharp // Mapper.Initialize or just the CreateMap snippet ``` -------------------------------- ### Expression Translation with Select and No ProjectTo Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Expression-Translation-(UseAsDataSource).md When a `Select` call after `UseAsDataSource()` changes the return type, `ProjectTo<>()` is not invoked. Instead, `mapper.Map` is used for the translation, as shown in this example where only the `Name` property is selected. ```csharp dataContext.OrderLines.UseAsDataSource().For().Select(dto => dto.Name) ``` -------------------------------- ### Translate a Simple Boolean Expression Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Expression-Translation-(UseAsDataSource).md Map a boolean expression from a DTO type to a source type. AutoMapper substitutes properties based on the defined mappings, translating `dto.Item` to `ol.Item.Name` in this example. ```csharp Expression> dtoExpression = dto=> dto.Item.StartsWith("A"); var expression = mapper.Map>>(dtoExpression); ``` -------------------------------- ### Reproduce Mapping Issues Source: https://github.com/luckypennysoftware/automapper/blob/main/ISSUE_TEMPLATE.md Provide your calls to Mapper.Map or ProjectTo here, along with constructed source and destination objects. This helps in reproducing and debugging mapping problems. ```csharp // Your calls to Mapper.Map or ProjectTo here, with source/destination objects constructed ``` -------------------------------- ### Enable PreserveReferences for Circular References Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/5.0-Upgrade-Guide.md Explicitly enable reference preservation for circular object graphs to avoid mapping issues. Starting from 6.1.0, this is often set automatically when recursion is detected. ```csharp cfg.CreateMap().PreserveReferences(); ``` -------------------------------- ### Configure Value Converter with Instance Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Value-converters.md Use a value converter instance for a specific member. Ensure the `CurrencyFormatter` class implements `IValueConverter`. ```csharp public class CurrencyFormatter : IValueConverter { public string Convert(decimal source, ResolutionContext context) => source.ToString("c"); } var configuration = new MapperConfiguration(cfg => { cfg.CreateMap() .ForMember(d => d.Amount, opt => opt.ConvertUsing(new CurrencyFormatter())); cfg.CreateMap() .ForMember(d => d.Total, opt => opt.ConvertUsing(new CurrencyFormatter())); }, loggerFactory); ``` -------------------------------- ### Global Property and Field Filtering Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Configuration.md Configure `ShouldMapField` and `ShouldMapProperty` to globally control which fields and properties AutoMapper attempts to map. For example, to skip all fields and map properties with public or private getters. ```csharp 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); }, loggerFactory); ``` -------------------------------- ### Inline Before/After Map Actions with Context Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Before-and-after-map-actions.md Execute before and after map actions with contextual information during the mapping process. This is useful when actions depend on runtime data. ```csharp int i = 10; mapper.Map(src, opt => { opt.BeforeMap((src, dest) => src.Value = src.Value + i); opt.AfterMap((src, dest) => dest.Name = HttpContext.Current.Identity.Name); }); ``` -------------------------------- ### Gather Configuration Before Initialization Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Setup.md Shows how to collect AutoMapper configuration using MapperConfigurationExpression before creating the MapperConfiguration instance. ```csharp var cfg = new MapperConfigurationExpression(); cfg.CreateMap(); cfg.AddProfile(); MyBootstrapper.InitAutoMapper(cfg); var mapperConfig = new MapperConfiguration(cfg, loggerFactory); IMapper mapper = new Mapper(mapperConfig); ``` -------------------------------- ### Add AutoMapper with Assemblies in ASP.NET Core Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Dependency-injection.md Use this extension method to register AutoMapper with your ASP.NET Core application, specifying assemblies that contain your profile configurations. Ensure AutoMapper.Extensions.Microsoft.DependencyInjection is installed for versions prior to 13.0. ```csharp services.AddAutoMapper(cfg => { }, profileAssembly1, profileAssembly2 /*, ...*/); ``` -------------------------------- ### Map to Destination Constructor Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Construction.md Map source members to destination constructor parameters by name. Ensure the constructor parameter names match the source member names. ```csharp public class Source { public int Value { get; set; } } public class SourceDto { public SourceDto(int value) { _value = value; } private int _value; public int Value { get { return _value; } } } var configuration = new MapperConfiguration(cfg => cfg.CreateMap(), loggerFactory); ``` -------------------------------- ### Add Attribute Maps to Configuration Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Attribute-mapping.md Use AddMaps to discover both fluent and attribute-based map configurations within specified assemblies. This method initializes the mapper with all found mappings. ```csharp var configuration = new MapperConfiguration(cfg => cfg.AddMaps("MyAssembly"), loggerFactory); var mapper = new Mapper(configuration); ``` -------------------------------- ### Configure and Perform Mapping Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Flattening.md Sets up AutoMapper to map the complex Order object to the OrderDto and then performs the mapping. This demonstrates the core flattening process. ```csharp // Complex model var customer = new Customer { Name = "George Costanza" }; var order = new Order { Customer = customer }; var bosco = new Product { Name = "Bosco", Price = 4.99m }; order.AddOrderLineItem(bosco, 15); // Configure AutoMapper var configuration = new MapperConfiguration(cfg => cfg.CreateMap(), loggerFactory); // Perform mapping OrderDto dto = mapper.Map(order); dto.CustomerName.ShouldEqual("George Costanza"); dto.Total.ShouldEqual(74.85m); ``` -------------------------------- ### Consolidate ConstructProjectionUsing with ConstructUsing Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/8.0-Upgrade-Guide.md Replace all usages of `ConstructProjectionUsing` with `ConstructUsing`. The `ConstructUsing` expression-based method now handles both in-memory mapping and LINQ projections. ```csharp // IMappingExpression // Old IMappingExpression ConstructUsing(Func ctor); IMappingExpression ConstructUsing(Func ctor); IMappingExpression ConstructProjectionUsing(Expression> ctorExpression); // New IMappingExpression ConstructUsing(Expression> ctor); IMappingExpression ConstructUsing(Func ctor); ``` ```csharp // IMappingExpression // Old IMappingExpression ConstructUsing(Func ctor); IMappingExpression ConstructUsing(Func ctor); IMappingExpression ConstructProjectionUsing(LambdaExpression ctorExpression); // New IMappingExpression ConstructUsing(Expression> ctor); IMappingExpression ConstructUsing(Func ctor); ``` -------------------------------- ### Configure License Key Directly with MapperConfiguration Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/License-configuration.md Set the license key directly in the constructor of MapperConfiguration for scenarios not using Microsoft.Extensions.DependencyInjection. A logger factory is required for this configuration. ```csharp var mapperConfiguration = new MapperConfiguration(cfg => { cfg.LicenseKey = "License Key Here"; }, loggerFactory); ``` -------------------------------- ### Parameterize Projection with Dictionary Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Queryable-Extensions.md Alternatively, use a dictionary to provide projection parameter values at runtime. Be aware that this can result in hard-coded values in the query, potentially bypassing parameterization. ```csharp dbContext.Courses.ProjectTo(Config, new Dictionary { {"currentUserName", Request.User.Name} }); ``` -------------------------------- ### Avoiding Duplicate License Messages with Manual MapperConfiguration Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/License-configuration.md When creating MapperConfiguration instances manually, each instance logs a license message. To avoid duplicates, create and reuse a single MapperConfiguration instance, typically registered as a singleton. ```csharp // Each of these logs a license message – avoid creating multiple instances var config1 = new MapperConfiguration(cfg => { cfg.LicenseKey = "key"; }, loggerFactory); var config2 = new MapperConfiguration(cfg => { cfg.LicenseKey = "key"; }, loggerFactory); ``` ```csharp // Create once and reuse var config = new MapperConfiguration(cfg => { cfg.LicenseKey = "key"; }, loggerFactory); var mapper = new Mapper(config); ``` -------------------------------- ### Default Property Resolution Logic (Conceptual) Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Custom-value-resolvers.md Illustrates the conceptual flow of resolving a destination property value, including attempting resolution and handling potential exceptions like NullReferenceException or ArgumentNullException by returning null. ```csharp try { var resolvedValue = { try { return // ... tries to resolve the destination value here } catch (NullReferenceException) { return null; } catch (ArgumentNullException) { return null; } }; if (condition.Invoke(src, typeMapDestination, resolvedValue)) { typeMapDestination.WorkStatus = resolvedValue; } } catch (Exception ex) { throw new AutoMapperMappingException( "Error mapping types.", ex, AutoMapper.TypePair, AutoMapper.TypeMap, AutoMapper.PropertyMap); }; ``` -------------------------------- ### Configure Value Converter via Service Locator Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Value-converters.md Instantiate the value converter using the service locator by specifying its type. This requires the converter to be registered in the service container. ```csharp public class CurrencyFormatter : IValueConverter { public string Convert(decimal source, ResolutionContext context) => source.ToString("c"); } var configuration = new MapperConfiguration(cfg => { cfg.CreateMap() .ForMember(d => d.Amount, opt => opt.ConvertUsing()); cfg.CreateMap() .ForMember(d => d.Total, opt => opt.ConvertUsing()); }, loggerFactory); ``` -------------------------------- ### Map Between Different Collection Types Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Lists-and-arrays.md Demonstrates mapping a source array to various destination collection types including IEnumerable, ICollection, IList, List, and arrays. ```csharp var configuration = new MapperConfiguration(cfg => cfg.CreateMap(), loggerFactory); var sources = new[] { new Source { Value = 5 }, new Source { Value = 6 }, new Source { Value = 7 } }; IEnumerable ienumerableDest = mapper.Map>(sources); ICollection icollectionDest = mapper.Map>(sources); IList ilistDest = mapper.Map>(sources); List listDest = mapper.Map>(sources); Destination[] arrayDest = mapper.Map(sources); ``` -------------------------------- ### IMappingAction with Dependency Injection Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Before-and-after-map-actions.md Implement IMappingAction to access dependencies like HttpContextAccessor. This allows for context-aware mapping logic that can be injected into your application. ```csharp public class SetTraceIdentifierAction : IMappingAction { private readonly IHttpContextAccessor _httpContextAccessor; public SetTraceIdentifierAction(IHttpContextAccessor httpContextAccessor) { _httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor)); } public void Process(SomeModel source, SomeOtherModel destination, ResolutionContext context) { destination.TraceIdentifier = _httpContextAccessor.HttpContext.TraceIdentifier; } } public class SomeProfile : Profile { public SomeProfile() { CreateMap() .AfterMap(); } } ``` -------------------------------- ### Global Before/After Map Actions Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Before-and-after-map-actions.md Define global before and after map actions within the MapperConfiguration. Use these for cross-cutting concerns that apply to all mappings. ```csharp var configuration = new MapperConfiguration(cfg => { cfg.CreateMap() .BeforeMap((src, dest) => src.Value = src.Value + 10) .AfterMap((src, dest) => dest.Name = "John"); }, loggerFactory); ``` -------------------------------- ### Define Source and Destination Classes Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Conditional-mapping.md Define the source and destination classes for mapping. ```csharp class Foo{ public int baz; } class Bar { public uint baz; } ``` -------------------------------- ### Configure Value Converter with Type and String Members Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Value-converters.md Use `System.Type` and string-based member names for runtime configuration when types or member names are not known at compile time. ```csharp public class CurrencyFormatter : IValueConverter { public string Convert(decimal source, ResolutionContext context) => source.ToString("c"); } var configuration = new MapperConfiguration(cfg => { cfg.CreateMap(typeof(Order), typeof(OrderDto)) .ForMember("Amount", opt => opt.ConvertUsing(new CurrencyFormatter(), "OrderAmount")); cfg.CreateMap(typeof(OrderLineItem), typeof(OrderLineItemDto)) .ForMember("Total", opt => opt.ConvertUsing(new CurrencyFormatter(), "LITotal")); }, loggerFactory); ``` -------------------------------- ### Use UseAsDataSource for Simplified Expression Mapping Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Expression-Translation-(UseAsDataSource).md Employ `UseAsDataSource().For()` to simplify expression translation and automatically call `ProjectTo()` when applicable. This reduces boilerplate code for common mapping scenarios. ```csharp dataContext.OrderLines.UseAsDataSource().For().Where(dto => dto.Name.StartsWith("A")) ``` -------------------------------- ### Compile Mappings Immediately Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Configuration.md Force AutoMapper to compile all type map plans immediately upon configuration using `CompileMappings()`. This can be useful for performance tuning by identifying long compilation times early. ```csharp var configuration = new MapperConfiguration(cfg => {}, loggerFactory); configuration.CompileMappings(); ``` -------------------------------- ### Migrate ProjectUsing to ConvertUsing Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/8.0-Upgrade-Guide.md Replace all usages of `ProjectUsing` with `ConvertUsing`. The `ConvertUsing` expression-based method is now used for both in-memory mapping and LINQ projections. ```csharp // IMappingExpression // Old void ConvertUsing(Func mappingFunction); void ProjectUsing(Expression> mappingExpression); // New void ConvertUsing(Expression> mappingExpression); ``` -------------------------------- ### Configure AutoMapper with Dependency Injection Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Before-and-after-map-actions.md Register AutoMapper services in your application's startup configuration to enable dependency injection for IMappingAction implementations. ```csharp public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddAutoMapper(_ => { }, typeof(Startup).Assembly); } //.. } ``` -------------------------------- ### Configure Type Mapping Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Getting-started.md Create a MapperConfiguration to define how source types map to destination types. This configuration should typically be done once during application startup. ```csharp var config = new MapperConfiguration(cfg => cfg.CreateMap(), loggerFactory); ``` -------------------------------- ### Update AddAutoMapper for License Requirement Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/15.0-Upgrade-Guide.md The AddAutoMapper overloads now require an Action parameter to specify the license key. This parameter is now the first argument. ```csharp // Previous services.AddAutoMapper(typeof(Program)); // Current services.AddAutoMapper(cfg => cfg.LicenseKey = "", typeof(Program)); ``` -------------------------------- ### Include All Derived Mappings Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Mapping-inheritance.md Conveniently include all derived maps from a base type map configuration. Note that this can be slower as it searches all mappings for derived types. ```csharp CreateMap() .IncludeAllDerived(); CreateMap(); ``` -------------------------------- ### Configure AutoMapper License Key Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/15.0-Upgrade-Guide.md Set your AutoMapper license key during service configuration. Obtain your license from https://automapper.io. ```csharp services.AddAutoMapper(cfg => { cfg.LicenseKey = ""; }); ``` -------------------------------- ### Configure License Key with Microsoft.Extensions.DependencyInjection Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/License-configuration.md Use this method to set the license key when integrating AutoMapper with Microsoft's dependency injection framework. Ensure the license key is provided within the configuration lambda. ```csharp services.AddAutoMapper(cfg => { cfg.LicenseKey = "License key here"; // Other configuration }); ``` -------------------------------- ### Handling Multiple AddAutoMapper Calls Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/License-configuration.md Calling AddAutoMapper multiple times is safe as subsequent calls are ignored after the initial registration of IMapper. This prevents redundant license validation. ```csharp services.AddAutoMapper(cfg => { cfg.LicenseKey = "key"; }); services.AddAutoMapper(cfg => { /* ignored -- IMapper already registered */ }); ``` -------------------------------- ### Scan Assembly for Profiles Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Configuration.md Automatically scan specified assemblies for classes inheriting from Profile and add them to the mapper configuration. This can be done using assembly instances, names, or marker types. ```csharp // Scan for all profiles in an assembly // ... using instance approach: var config = new MapperConfiguration(cfg => { cfg.AddMaps(myAssembly); }, loggerFactory); var configuration = new MapperConfiguration(cfg => cfg.AddMaps(myAssembly), loggerFactory); ``` ```csharp // Can also use assembly names: var configuration = new MapperConfiguration(cfg => { cfg.AddMaps(new [] { "Foo.UI", "Foo.Core" }); }, loggerFactory); ``` ```csharp // Or marker types for assemblies: var configuration = new MapperConfiguration(cfg => { cfg.AddMaps(new [] { typeof(HomeController), typeof(Entity) }); }, loggerFactory); ``` -------------------------------- ### Configure Mapping Profile in AutoMapper 5.0 Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/5.0-Upgrade-Guide.md Define custom mapping logic by inheriting from Profile and configuring maps within the constructor. Use RecognizePrefix to specify prefixes for member recognition. ```csharp public class MappingProfile : Profile { public MappingProfile() { CreateMap(); RecognizePrefix("m_"); } } ``` -------------------------------- ### Define Source and Destination Types Source: https://github.com/luckypennysoftware/automapper/blob/main/ISSUE_TEMPLATE.md Place your source and destination type definitions here. This is a placeholder for your custom classes. ```csharp // Put your source/destination types here ``` -------------------------------- ### Define Source and Destination Types Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Configuration-validation.md Define the source and destination classes for mapping. Ensure property names match or are configured for mapping. ```csharp public class Source { public int SomeValue { get; set; } } public class Destination { public int SomeValuefff { get; set; } } ``` -------------------------------- ### Precondition Mapping with Inline Lambda Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Conditional-mapping.md Use a precondition to run a check before the source value is resolved. This can prevent expensive resolution processes if the condition fails. ```csharp var configuration = new MapperConfiguration(cfg => { cfg.CreateMap() .ForMember(dest => dest.baz, opt => { opt.PreCondition(src => (src.baz >= 0)); opt.MapFrom(src => { // Expensive resolution process that can be avoided with a PreCondition }); }); }, loggerFactory); ``` -------------------------------- ### Implement Custom Destination Factory Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Construction.md Create a custom class implementing IDestinationFactory to define specific object construction logic. This allows for reusable and dependency-injection-friendly instantiation. ```csharp public interface IDestinationFactory { TDestination Construct(TSource source, ResolutionContext context); } public class CustomConstructor : IDestinationFactory { public Destination Construct(Source source, ResolutionContext context) { // Custom instantiation logic return new Destination { InitialValue = source.Value * 2 }; } } cfg.CreateMap() .ConstructUsing(); ``` -------------------------------- ### Inspect IQueryable Expression for ProjectTo Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Understanding-your-mapping.md Access the underlying expression tree generated by `ProjectTo` for `IQueryable` sources. This is useful for understanding how the projection is translated into a query. Remove this code before release. ```csharp var expression = context.Entities.ProjectTo().Expression; ``` -------------------------------- ### Define Classes for Flattened Property Mapping Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Expression-Translation-(UseAsDataSource).md Define the data model classes (`Course`, `Department`) and the view model/DTO classes (`CourseModel`) for demonstrating flattened property mapping. ```csharp public class CourseModel { public int CourseID { get; set; } public int DepartmentID { get; set; } public string DepartmentName { get; set; } } public class Course { public int CourseID { get; set; } public int DepartmentID { get; set; } public Department Department { get; set; } } public class Department { public int DepartmentID { get; set; } public string Name { get; set; } } ``` -------------------------------- ### Dependency Injection with Destination Factory Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Construction.md Implement a destination factory that utilizes dependency injection for services. The factory's constructor can accept injected services to perform custom calculations during object construction. ```csharp public class DIAwareConstructor : IDestinationFactory { 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(); services.AddAutoMapper(cfg => { cfg.CreateMap() .ConstructUsing(); }, typeof(IMyService).Assembly); ``` -------------------------------- ### Encapsulate AfterMap Action with IMappingAction Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Before-and-after-map-actions.md Encapsulate reusable mapping logic into a class implementing IMappingAction. This promotes code organization and reusability for common post-mapping tasks. ```csharp public class NameMeJohnAction : IMappingAction { public void Process(SomePersonObject source, SomeOtherPersonObject destination, ResolutionContext context) { destination.Name = "John"; } } var configuration = new MapperConfiguration(cfg => { cfg.CreateMap() .AfterMap(); }); ``` -------------------------------- ### Define Source and Destination Types Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Lists-and-arrays.md Define simple source and destination types for mapping. ```csharp public class Source { public int Value { get; set; } } public class Destination { public int Value { get; set; } } ``` -------------------------------- ### Execute Projection Query Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Queryable-Extensions.md Use the configured projection with the ProjectTo method on an IQueryable to fetch data. This method should be the last in the LINQ chain to ensure optimal query generation by the ORM. ```csharp public List GetLinesForOrder(int orderId) { using (var context = new orderEntities()) { return context.OrderLines.Where(ol => ol.OrderId == orderId) .ProjectTo(configuration).ToList(); } } ``` -------------------------------- ### Customize Reverse Map with ForPath Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Reverse-Mapping-and-Unflattening.md Customizes the reverse mapping for 'Customer.Name' using 'ForPath' when the source and destination paths differ. This is typically not needed if 'MapFrom' uses simple member accessors. ```csharp cfg.CreateMap() .ForMember(d => d.CustomerName, opt => opt.MapFrom(src => src.Customer.Name)) .ReverseMap() .ForPath(s => s.Customer.Name, opt => opt.MapFrom(src => src.CustomerName)); ``` -------------------------------- ### Inject IMapper in ASP.NET Core Controller Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Dependency-injection.md Demonstrates how to inject the `IMapper` interface into an ASP.NET Core controller's constructor to utilize AutoMapper's mapping capabilities within your application's services. ```csharp public class EmployeesController { private readonly IMapper _mapper; public EmployeesController(IMapper mapper) => _mapper = mapper; // use _mapper.Map or _mapper.ProjectTo } ``` -------------------------------- ### Set Source and Destination Naming Conventions Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Configuration.md Configure source and destination member naming conventions for the mapper. This allows for automatic mapping between properties with different naming styles, such as underscore_case to PascalCase. ```csharp var configuration = new MapperConfiguration(cfg => { cfg.SourceMemberNamingConvention = LowerUnderscoreNamingConvention.Instance; cfg.DestinationMemberNamingConvention = PascalCaseNamingConvention.Instance; }, loggerFactory); ``` -------------------------------- ### Execute AutoMapper Mappings Source: https://github.com/luckypennysoftware/automapper/blob/main/README.md Execute mappings using the created mapper instance. This is typically done after configuring AutoMapper. ```csharp var fooDto = mapper.Map(foo); var barDto = mapper.Map(bar); ``` -------------------------------- ### Build AutoMapper Execution Plan Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Understanding-your-mapping.md Use this to inspect the execution plan of a mapping between two types during debugging. Ensure this code is removed before production. ```csharp var configuration = new MapperConfiguration(cfg => cfg.CreateMap(), loggerFactory); var executionPlan = configuration.BuildExecutionPlan(typeof(Foo), typeof(Bar)); ``` -------------------------------- ### Class-Based Conditions with Dependency Injection Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Conditional-mapping.md Implement conditions that utilize dependency injection by injecting services into the condition class constructor. ```csharp public class AgeRestrictedContentCondition : ICondition { private readonly IAgeRestrictionService _ageService; public AgeRestrictedContentCondition(IAgeRestrictionService ageService) { _ageService = ageService; } public bool Evaluate(User source, UserDto destination, int sourceMember, int destMember, ResolutionContext context) => _ageService.CanAccessAdultContent(sourceMember); } // Registration services.AddScoped(); services.AddAutoMapper(cfg => { cfg.CreateMap() .ForMember(d => d.RestrictedContent, o => { o.Condition(); o.MapFrom(s => s.RestrictedContent); }); }); ``` -------------------------------- ### Validate Member Mappings with MemberList.None Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/5.0-Upgrade-Guide.md Use the MemberList enum with CreateMap to validate mappings against source members or no members. This replaces the IgnoreAllNonExisting extension for configuration validation. ```csharp cfg.CreateMap(MemberList.None); ``` -------------------------------- ### Commit/Pull Request Format Source: https://github.com/luckypennysoftware/automapper/blob/main/CONTRIBUTING.md Follow this format for commit messages and pull requests to ensure clarity and consistency. Include a concise summary and detailed points, along with any relevant bug numbers. ```markdown Summary of the changes (Less than 80 chars) - Detail 1 - Detail 2 #bugnumber (in this specific format) ``` -------------------------------- ### Define Entities for Projection Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Queryable-Extensions.md Define the source entities that will be mapped. Ensure all necessary properties are present. ```csharp public class OrderLine { public int Id { get; set; } public int OrderId { get; set; } public Item Item { get; set; } public decimal Quantity { get; set; } } public class Item { public int Id { get; set; } public string Name { get; set; } } ``` -------------------------------- ### Redirect Base Map to Derived Map with As Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Mapping-inheritance.md Use the `As` method to redirect a base map to an existing derived map for simple inheritance scenarios. This is useful when a base type should always map to a specific derived DTO type. ```csharp cfg.CreateMap(); cfg.CreateMap().As(); mapper.Map(new Order()).ShouldBeOfType(); ``` -------------------------------- ### Configure Basic Reverse Map Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Reverse-Mapping-and-Unflattening.md Configures AutoMapper to map between 'Order' and 'OrderDto' in both directions using 'ReverseMap()'. This enables unflattening by default. ```csharp var configuration = new MapperConfiguration(cfg => { cfg.CreateMap() .ReverseMap(); }, loggerFactory); ``` -------------------------------- ### Configure Reverse Map with MapFrom Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Reverse-Mapping-and-Unflattening.md Configures a reverse map where the 'CustomerName' in 'OrderDto' is explicitly mapped from 'Order.Customer.Name' using 'MapFrom'. AutoMapper attempts to reverse this flattening automatically. ```csharp cfg.CreateMap() .ForMember(d => d.CustomerName, opt => opt.MapFrom(src => src.Customer.Name)) .ReverseMap(); ``` -------------------------------- ### Set Naming Conventions within a Profile Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Configuration.md Apply specific source and destination naming conventions to a particular mapping profile. This allows for different naming conventions across different sets of mappings. ```csharp public class OrganizationProfile : Profile { public OrganizationProfile() { SourceMemberNamingConvention = LowerUnderscoreNamingConvention.Instance; DestinationMemberNamingConvention = PascalCaseNamingConvention.Instance; //Put your CreateMap... Etc.. here } } ``` -------------------------------- ### Specify Inheritance in Derived Classes Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Mapping-inheritance.md Configure inheritance from the derived classes by using `IncludeBase` in the derived type's mapping configuration. This allows the derived map to inherit configurations from its base type. ```csharp var configuration = new MapperConfiguration(cfg => { cfg.CreateMap() .ForMember(o => o.Id, m => m.MapFrom(s => s.OrderId)); cfg.CreateMap() .IncludeBase(); cfg.CreateMap() .IncludeBase(); }, loggerFactory); ``` -------------------------------- ### Custom Projection with Member Mapping Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Queryable-Extensions.md Use MapFrom to define custom expressions for destination members, such as combining source properties or calculating values. ```csharp var configuration = new MapperConfiguration(cfg => cfg.CreateProjection() .ForMember(d => d.FullName, opt => opt.MapFrom(c => c.FirstName + " " + c.LastName)) .ForMember(d => d.TotalContacts, opt => opt.MapFrom(c => c.Contacts.Count())), loggerFactory); ``` -------------------------------- ### Select Members for Validation Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Configuration-validation.md Control which members are validated during configuration. By default, all destination members are validated. Use `MemberList.Source` to validate only source members, or `MemberList.None` to skip validation for a map. ```csharp var configuration = new MapperConfiguration(cfg => cfg.CreateMap(MemberList.Source); cfg.CreateMap(MemberList.None); , loggerFactory); ``` -------------------------------- ### Configure Null Substitution for a Member Source: https://github.com/luckypennysoftware/automapper/blob/main/docs/source/Null-substitution.md Use NullSubstitute to define an alternative value for a destination member when the source member is null. The substitute value is subject to the same mapping and conversion rules as regular source values. ```csharp var config = new MapperConfiguration(cfg => cfg.CreateMap() .ForMember(destination => destination.Value, opt => opt.NullSubstitute("Other Value")), loggerFactory); var source = new Source { Value = null }; var mapper = config.CreateMapper(); var dest = mapper.Map(source); dest.Value.ShouldEqual("Other Value"); source.Value = "Not null"; dest = mapper.Map(source); dest.Value.ShouldEqual("Not null"); ```