Wednesday 13 December 2017

Basic of AutoMapper in C#

AutoMapper is a dll which is used to mapped one object to another.
  • No longer need to manually map objects.
  • Good to use for ViewModel/CreateModel, Request/Response entity.
  • Least used features of AutoMapper is projection. AutoMapper, when used with an Object Relational Mapper (ORM) such as Entity Framework,

How to Use?

Just Install it through Nuget Package manager and use it.



using AutoMapper;
using AutomapperDemo.Models;
using static System.Console;
 
namespace AutomapperDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            User user = new User()
            {
 
                ID = 100,
                FirstName = "Raj",
                LastName = "Kumar",
                Address = "Delhi",
                Company = "AAPC",
                Dept = "IT",
                OfficialEmail = "blog.raj111@gmail.com",
                FatherName = "R.J.T",
                Gender = "Male",
                Maritialstatus = "Married",
                Mobile = "8888888888"
            };
 
            Mapper.Initialize(config =>
            {
 
                config.CreateMap<UserUserPersonalInfo>();//All properties are same
 
                config.CreateMap<UserUserOfficialInfo>()
                    .ForMember(d => d.UserID, m => m.MapFrom(s => s.ID));//Map different property 
 
                config.CreateMap<UserUserViewModel>()
                    .ForMember(d => d.Name, m => m.MapFrom(s => s.FirstName + " " + s.LastName))//Modify property
                    .ForMember(d => d.ID, m => m.Ignore());//Ignore Default mapping
 
            });
 
 
            var personalInfo = Mapper.Map<UserUserPersonalInfo>(user);
            var officialInfo = Mapper.Map<UserUserOfficialInfo>(user);
            var userViewModel = Mapper.Map<UserUserViewModel>(user);
 
            //Explicit mapping through configuration
            var userProfileInfo = AutoMapperSetup.UserProfileInfoConfig.CreateMapper().Map<UserProfileInfo>(user);
 
            Read();
 
        }
    }
}
 
 
 
namespace AutomapperDemo.Models
{
    class User
    {
        public int ID { getset; }
        public string FirstName { getset; }
        public string LastName { getset; }
        public string FatherName { getset; }
        public string Gender { getset; }
        public string Maritialstatus { getset; }
        public string Mobile { getset; }
        public string OfficialEmail { getset; }
        public string Address { getset; }
        public string Company { getset; }
        public string Dept { getset; }
 
    }
    class UserOfficialInfo
    {
        public int UserID { getset; }
        public string OfficialEmail { getset; }
        public string Address { getset; }
        public string Company { getset; }
        public string Dept { getset; }
    }
 
    class UserPersonalInfo
    {
        public string FirstName { getset; }
        public string LastName { getset; }
        public string FatherName { getset; }
        public string Gender { getset; }
        public string Maritialstatus { getset; }
        public string Mobile { getset; }
    }
 
    class UserViewModel
    {
        public int ID { getset; }
        public string Name { getset; }
        public string FatherName { getset; }
        public string Gender { getset; }
 
    }
 
    class UserProfileInfo
    {
        public int ID { getset; }
        public string Name { getset; }
    }
}
 
namespace AutomapperDemo.Models
{
    //This is how we can explicit define the configuration and later on can create mapper on demand.  
    public static class AutoMapperSetup
    {
        public static MapperConfiguration UserProfileInfoConfig = new MapperConfiguration(config =>
        {
            config.CreateMap<UserUserProfileInfo>()
            .ForMember(dto => dto.ID, conf => conf.MapFrom(src => src.ID))
            .ForMember(dto => dto.Name, conf => conf.MapFrom(src => $"{src.FirstName} {src.LastName}"));
        });
    }
}


How to Map reverse or Vice versa in AutoMapper?

Just taking the example of above code if we add one more line

var reverseUser = Mapper.Map<UserViewModel, User>(userViewModel);

It will throw an error:

Unmapped members were found. Review the types and members below.
Add a custom mapping expression, ignore, add a custom resolver, or modify the source/destination type
For no matching constructor, add a no-arg ctor, add optional arguments, or map all of the constructor parameters
==================================================================
AutoMapper created this type map for you, but your types cannot be mapped using the current configuration.
UserViewModel -> User (Destination member list)
AutomapperDemo.Models.UserViewModel -> AutomapperDemo.Models.User (Destination member list)

Unmapped properties:
FirstName
LastName
Maritialstatus
Mobile
OfficialEmail
Address
Company
Dept

This is because we haven't instructed AutoMapper to map object reversely, so what we need to do here is, while configuring Createmap we need to call one one method  ReverseMap().


config.CreateMap<UserUserViewModel>()
    .ForMember(d => d.Name, m => m.MapFrom(s => s.FirstName + " " + s.LastName))//Modify property
    .ForMember(d => d.ID, m => m.Ignore()) //Ignore Default mapping
    .ReverseMap() //We can again set .ForMember for reverse value if needed.
    ;

How to map case sensitive fields or object names in Automapper?

Auto-mapper having functionality to map case sensitive or custom conditional mapping with fields.
Like in the above example if i create a new Model

class User_view_model
{
    public int Id { getset; }
    public string Name { getset; }
    public string Father_name { getset; }
    public string Gender { getset; }
 
}

And want to map it like this
var underscore = Mapper.Map<UserViewModelUser_view_model>(userViewModel);

We can use it by just configuring conditional mapping
// for the auto mapping with MyNameIsRaj to My_name_is_raj.
config.AddConditionalObjectMapper().Where((s, d) => s.Name == d.Name.ToUnderscoreCase());

You would also required an extension method
public static class StringExtensions
{
    public static string ToUnderscoreCase(this string str)
    {
        return string.Concat(str.Select((x, i) => i > 0 && char.IsUpper(x) ? "_" + x.ToString() : x.ToString())).ToLower();
    }
}

Reference:

http://automapper.org/
https://www.codeproject.com/Articles/61629/AutoMapper
https://www.codeproject.com/Articles/814869/AutoMapper-tips-and-tricks