Click here to Skip to main content
14,208,441 members
Click here to Skip to main content
Add your own
alternative version

Tagged as

Stats

23.8K views
4 bookmarked
Posted 23 Jun 2015
Licenced CPOL

Using AutoMapper in Your Application for Translating Source Object to Destination Object

Rate this:
Please Sign up or sign in to vote.
How to use AutoMapper in your application for translating source object to destination object

Most of us, at some time, have faced a situation where we need to convert the data contract objects to corresponding data model object. I agree, it is very easy to do so. We just need to write some static methods to convert one type of object to another. However this task is very boring. Also, you need to be careful while translating each source property to correct destination property, especially when copying things in this case. You need to be careful enough to handle null values.

So what is the solution then? Yes, our friend has already written a library for you to do this repetitive and boring task. Along with this, it provides you variety of ways to do this. You can configure things as per your requirement. Now without waiting any more, let's know more and in detail about what is AutoMapper and how to use it.

What is AutoMapper?

  • Object-Object Mapper – Translated object of one class to object of its counterpart class.
  • Nuget Package – You can get AutoMapper using Nuget Package manager since it is shared through Nuget.

What are the Things to Know About AutoMapper?

  • It ignores null reference exceptions when mapping your source to your target.
  • It does the dirty work for you of figuring out how to map type A to type B.
  • As long as type B follows AutoMapper’s established convention, almost zero configuration is needed to map two types.
  • It provides simple configuration of types, as well as simple testing of mappings.
  • AutoMapper also supports Flattening.

What are the Simple Steps to Use AutoMapper?

  • Open Visual Studio.
  • Create a new project (Windows/Web). I created console application.
  • Install AutoMapper into your project using Nuget Package Manager UI or Nuget Package Manager Console. I used the below command to install it through console. It will install the latest version of AutoMapper.
    Install-Package AutoMapper
  • Create two classes “Source.cs” and “Dest.cs” as below:
    namespace Demo.AppCode
    {
    	public class Source
    	{
    		public int Id { get; set; }
    
    		public string Value { get; set; }
    	}
    }
    
    namespace Demo.AppCode
    {
    	public class Dest
    	{
    		public int Id { get; set; }
    
    		public string Value { get; set; }
    
    	}
    }
  • Use Mapper.Map() to convert source object to destination object as below:
    using System;
    using AutoMapper;
    using Demo.AppCode;
    
    namespace Demo
    {
    	class Program
    	{
    		static void Main(string[] args)
    		{
    			//Create an object of Source class with some values
    			var aSourceObject = new Source()
    			{
    				Id = 1000,
    				Value = "Test Value"
    			};
    
    			//Create the map for Source and Dest classes. 
                //It is internally used by AutoMapper to create mapping of properties. 
                //This statement should exist only once in your application.
    			Mapper.CreateMap<Source, Dest>();
    
    			//Translate or Convert Source class object to Dest class object.
    			var aDestObject = Mapper.Map<Dest>(aSourceObject);
    
    
    			//Verify that both Source and Dest class objects has the same values.
    			Console.WriteLine("Source.Id = {0}          
                                   Dest.Id={1}", aSourceObject.Id, aDestObject.Id);
    			Console.WriteLine("Source.Value = {0}       
                                   Dest.Value={1}", aSourceObject.Value, aDestObject.Value);
    			Console.ReadKey();
    		}
    	}
    }

The above example is the simplest example of using AutoMapper in your application. You can have some more properties in your classes. Apart from this, you can do some custom configuration. We will see such examples soon.

Where Should I Configure AutoMapper?

If you’re using the static Mapper method, configuration should only happen once per AppDomain/Application. That means the best place to put the configuration code is in application startup, such as the Global.asax file > Application_Start() method for ASP.NET applications. Typically, the configuration bootstrapper class is in its own class, and this bootstrapper class is called from the startup method.

What Do You Mean by bootstrapper Class in the Above Statement?

Bootstrapper class is a general class in our application where we create a method, say “Initialize()” and we put all the initialization related code blocks. These code blocks are supposed to run only once. In this way, it is easy to maintain this code block. It is good practice that we create a startup.cs file in our application at root and use this class wherever needed. In this case, we can call Startup.CreateMappings() in Global.asax > Application_Start() method.

How Can I Test My Mappings?

To test your mappings, you need to create a test that calls your bootstrapper class say “Startup.CreateMappings()” to create all the mappings and call Mapper.AssertConfigurationIsValid() method which should verify if there is any issue with your mappings. Below is the example:

using AutoMapper;
using Demo.AppCode;

namespace Demo
{
	public static class Startup
	{
		public static void CreateMappings()
		{
			//Create the map for Source and Dest classes. 
            //It is internally used by AutoMapper to create mapping of properties.
			Mapper.CreateMap<Source, Dest>();

			//Validate the mappings done above
			Mapper.AssertConfigurationIsValid();
		}
	}
}

What is Flattening? Can You Give An Example Using AutoMapper?

There are times when you have a complex object having child objects with their own child object and so on. In this case, you may need to translate this complex object to some other simple object which contains only few properties out of the complex object.

So converting the complex object (having nested child objects) to simple object (having single level of properties) is called Flattening.

AutoMapper does support Flattening. Below is an example which gives you an idea about how to do it:

using System;
using System.Collections.Generic;
using AutoMapper;
using Demo.AppCode;

namespace Demo
{
	class Program
	{
		static void Main(string[] args)
		{
//Create the mappings when application starts
			Startup.CreateMappings();

//Create an object of Complex class with sample data
			var aComplexObject = new Complex()
			{
				Other = new Other(){Name = "Other child"},
				Childs = new List<Child>()
				{
					new Child(){ChildId = 101, ChildValue = "Value1"},
					new Child(){ChildId = 102, ChildValue="Value2"}
				}
			};

//Translate complex object to simple object
			var aSimpleObject = Mapper.Map<Simple>(aComplexObject);

			//Verify that simple object has expected value,
            //i.e. Othername = "Other child" and TotalChildCount = 2.
			Console.WriteLine("SimpleObject.OtherName = {0}", aSimpleObject.OtherName);
			Console.WriteLine("SimpleObject.TotalChildCount = {0}", aSimpleObject.TotalChildCount);
			Console.ReadKey();
		}
	}
}
using System.Collections.Generic;

namespace Demo.AppCode
{
	public class Complex
	{
		public Other Other { get; set; }
		
		public IList<Child> Childs { get; set; }

		public int GetTotalChildCount()
		{
			return Childs == null ? 0 : Childs.Count;
		}
	}

	public class Other
	{
		public string Name { get; set; }
	}

	public class Child
	{
		public int ChildId { get; set; }

		public string ChildValue { get; set; }
	}	
}

namespace Demo.AppCode
{
	public class Simple
	{
		public string OtherName { get; set; }
		public int TotalChildCount { get; set; }
	}
}

What are the Rules/Conventions of AutoMapper Which We Should Follow to Get Better Result?

Following are some important conventions you should remember while using AutoMapper:

  • When you configure a source/destination type pair in AutoMapper, its configurator attempts to match properties and methods on the source type to properties on the destination type. If for any property on the destination type a property, method, or a method prefixed with “Get” exist on the source type, AutoMapper assigns its value to the corresponding property (without “Get”) in destination type.
  • When you configure a source/destination type pair in AutoMapper, its configurator attempts to match properties and methods on the source type to properties on the destination type. If for any property on the destination type a property, method, or a method prefixed with “Get” does not exist on the source type, AutoMapper splits the destination member name into individual words (by PascalCase conventions).

What is Custom Value Resolver in AutoMapper? When and How to Use It in My Application?

Although AutoMapper covers quite a few destination member mapping scenarios, there are the scenarios where AutoMapper needs a little help in resolving. For this, we need to create our own resolver.

Steps to Use Custom Value Resolver in AutoMapper

  • Create two classes, Source and Destination.
  • Create custom value resolver by inheriting AutoMapper class “ValueResolver<S,T>”. Here S represents source class data type and T represents the property datatype in destination class.
  • Tell AutoMapper to use this custom value resolver when resolving a specific destination member/property. We have several options in telling AutoMapper a custom value resolver to use, including:
//Resolve using Interface. Gives flexibility to use any resolver which implement this interface
ResolveUsing<TValueResolver>

//Resolve using custom resolver.
ResolveUsing(typeof(CustomValueResolver))

//Resolve using instance of custom resolver
ResolveUsing(aValueResolverInstance)

Below is an example which demonstrates the use of custom AutoMapper resolver to resolve Source class object to Dest class object.

using System;
using AutoMapper;

namespace Demo
{
	public class Source
	{
		public int Id { get; set; }

		public string Value { get; set; }
	}

	public class Dest
	{
		public string IdAndValue { get; set; }
	}

	//Create custom resolver.
	public class SourceToDestResolver : ValueResolver<Source, string>
	{
		protected override string ResolveCore(Source theSource)
		{
			return string.Format("Id with Value: {0}-{1}", theSource.Id, theSource.Value);
		}
	}

	class Program
	{
		static void Main(string[] args)
		{
			//Register mapping with SourceToDestResolver
			Mapper.CreateMap<Source, Dest>()
				.ForMember(dest => dest.IdAndValue, opt => opt.ResolveUsing<SourceToDestResolver>());

			//Create object of Source class with sample values
			var aSource = new Source() {Id = 1001, Value = "Any Value"};

			//Get object of Dist class using AutoMapper custom resolver "SourceToDestResolver"
			var aDest = Mapper.Map<Source, Dest>(aSource);
			
			//Verify that mapping is working as expected
			Console.WriteLine("Source Id: {0}            Source Value: {1}", aSource.Id, aSource.Value);
			Console.WriteLine("Destination IdWithValue: {0}", aDest.IdAndValue);

			Console.ReadKey();
		}
	}
}

Can We Instruct AutoMapper to Use Custom Constructor Methods to Create Object of Custom Resolver Instead of Reflection? If Yes, How?

Because we only supplied the type of the custom resolver to AutoMapper, the mapping engine will use reflection to create an instance of the value resolver.

If we don’t want AutoMapper to use reflection to create the instance, we can either supply the instance directly, i.e., ResolveUsing(aValueResolverInstance), or use the ConstructedBy method to supply a custom constructor method:

Mapper.CreateMap<Source, Destination>()
        .ForMember(dest => dest.IdWithValue, 
            opt => opt.ResolveUsing<SourceToDestResolver>().ConstructedBy(() => 
                   new SourceToDestResolver())
        );

AutoMapper will execute callback function instead of using reflection during the mapping operation, helpful in scenarios where the resolver might have constructor arguments or need to be constructed by an IoC container.

How Can You Customize the Source Value Supplied to the Resolver?

By default, AutoMapper passes the source object to the resolver. This limits the reusability of resolvers, since the resolver is coupled to the source type. If, however, we supply a common resolver across multiple types, we configure AutoMapper to redirect the source value supplied to the resolver:

Mapper.CreateMap<Source, Dest>()
    .ForMember(dest => dest.Total,
        opt => opt.ResolveUsing<SourceToDestResolver>().FromMember(src => src.SubTotal));
Mapper.CreateMap<OtherSource, OtherDest>()
    .ForMember(dest => dest.OtherTotal,
        opt => opt.ResolveUsing<SourceToDestResolver>().FromMember(src => src.OtherSubTotal));

public class CustomResolver : ValueResolver<decimal, decimal> {
// logic here
}

Can You Modify the Value of Source Object Before and After Map Actions? If Yes, How?

Occasionally, you might need to perform custom logic before or after a map occurs. In this case, you can create global before/after map actions. For example, you may want to validate the source values or trim strings:

Mapper.CreateMap<Source, Dest>()
    .BeforeMap((src, dest) => src.Value = src.Value + 10) //Custom processing of adding 10.
    .AfterMap((src, dest) => dest.Name = src.Name.Trim()); //Trim before conversion

You can also create before/after map callbacks during mapping:

Mapper.Map<Source, Dest>(src, opt => {
    opt.BeforeMap((src, dest) => src.Value = src.Value + 10);
    opt.AfterMap((src, dest) => dest.Name = HttpContext.Current.Identity.Name);
});

What is Conditional Mapping in AutoMapper? How To Do It?

AutoMapper allows you to add conditions to properties that must be met before that property will be mapped. In other words, you can validate the properties before translation.

//Validate that the Id is greater than zero before translation
Mapper.CreateMap<Source,Dest>()
  .ForMember(dest => dest.Id, opt => opt.Condition(src => (src.Id > 0))); 

What is “Null Substitution” in AutoMapper?

“Null substitution” allows you to supply an alternate value for a destination member if the source value is null anywhere along the member chain.

//Assign "India" as default country name if it is not assigned in source object
Mapper.CreateMap<Source, Dest>()
    .ForMember(dest => dest.Country, opt => opt.NullSubstitute("India"));

Does AutoMapper Support Nested Mapping?

Yes, AutoMapper supports Nested Mapping. As the mapping engine executes the mapping, it can use one of a variety of methods to resolve a destination member value. One of these methods is to use another type map, where the source member type and destination member type are also configured in the mapping configuration. This allows us to not only flatten our source types, but create complex destination types as well.

In this case, you need to create mapping for source object type along with nested child object types:

Mapper.CreateMap<OuterSource, OuterDest>();
Mapper.CreateMap<InnerSource, InnerDest>();
Mapper.CreateMap<MostInnerSource, MostInnerDest>();

Do We Need to Create Mapping for List/Array/Collection?

No, we do not need to create mapping for List/Array/Collection. AutoMapper only requires configuration of element types, not of any array or list type that might be used.

How AutoMapper Translated Source Types Which Inherits Some Other Classes?

In such scenario where we have a hierarchy of types in both our source and destination types. AutoMapper supports polymorphic arrays and collections, such that derived source/destination types are used if found.

AutoMapper still requires explicit configuration for child mappings, as AutoMapper cannot “guess” which specific child destination mapping to use. Here is an example of the above types:

//ParentCource:ChildSource
//ParentDestination:ChildDestination
Mapper.CreateMap<ParentSource, ParentDestination>()
        .Include<ChildSource, ChildDestination>();
Mapper.CreateMap<ChildSource, ChildDestination>();

Hope it will help you understand about the concepts of AutoMapper and how to use it in your application. Let me know if you want some more details about it. I would be glad to help.

References

Please refer to AutoMapper for more details.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author


Comments and Discussions

 
QuestionDoes it make sense to use Automapper if source and destination properties(names) are totally different. Pin
User@Rupesh16-Oct-15 6:14
memberUser@Rupesh16-Oct-15 6:14 
AnswerRe: Does it make sense to use Automapper if source and destination properties(names) are totally different. Pin
Adarsh Chaurasia - Passionate Trainer28-Oct-15 4:31
professionalAdarsh Chaurasia - Passionate Trainer28-Oct-15 4:31 
AnswerMapping using Expression Tree in C# Pin
Liju Sankar17-Jul-15 5:28
professionalLiju Sankar17-Jul-15 5:28 
QuestionAutoMapper is not the fastest Pin
Member 1056055625-Jun-15 23:38
professionalMember 1056055625-Jun-15 23:38 
AnswerRe: AutoMapper is not the fastest Pin
Adarsh Chaurasia - Passionate Trainer6-Jul-15 23:42
professionalAdarsh Chaurasia - Passionate Trainer6-Jul-15 23:42 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Cookies | Terms of Use | Mobile
Web03 | 2.8.190612.1 | Last Updated 24 Jun 2015
Article Copyright 2015 by Adarsh Chaurasia - Passionate Trainer
Everything else Copyright © CodeProject, 1999-2019
Layout: fixed | fluid