AutoMapper is an object-to-object mapper, that enable mapping objects to another object when it is needed, sometimes we need to Map our Model to ViewModel and vice Versa. It is very useful when you are going to Map your Model to View Model especially when you are going through MVVM or MVC pattern. Fire Up visual studio, Create an MVC Project and create a class with this definition in your solution :
public class User { public Guid UserId { get; set; } public string Name { get; set; } public string Address { get; set;} }
And create IUserRepository interface :
public interface IUserRepository { IEnumerable<User> GetAll(); User GetById(Guid userId); }
And then create the UserRepository Class the implements the IUserRepository members :
public class UserRepository :IUserRepository { public IEnumerable<User> GetAll() { throw new NotImplementedException(); } public User GetById(Guid userId) { throw new NotImplementedException(); } }
Now create the ViewModel Class like this
public class UserViewModel { public Guid UserId { get; set; } public string Name { get; set; } public string Address { get; set; } }
Then create IUserService class in your solution like this :
public interface IUserService { IEnumerable<UserViewModel> GetAllUser(); UserViewModel GetBy(Guid userId); }
needless to say, the service class implements the interface methods
public class UserService :IUserService { private readonly IUserRepository _userRepository; public UserService(IUserRepository userRepository) { _userRepository = userRepository; } public IEnumerable<UserViewModel> GetAllUser() { throw new NotImplementedException(); } public UserViewModel GetBy(Guid userId) { throw new NotImplementedException(); } }
Well, to show a specific User and all of the User in UI, create a controller with this definition :
public class AutoMapperController : Controller { private readonly IUserService _userService; public AutoMapperController (IUserService userService) { _userService = userService; } public ViewResult UserList() { var users = _userService.GetAllUser(); return View(users); } public ViewResult UserInfo(Guid userId) { var user = _userService.GetBy(userId); return View(user); } }
So in big Applications Service should convert Model to ViewModel (they call DTO too) and we should Map the Model Entities to ViewModel, to get this add a class named Mapping to the solution : (it is better to write Mapper methods as the extension to make them accessible everywhere it is needed)
public static class Mapping { public static UserViewModel ConvertToUserView(this User user) { var userViewModel = new UserViewModel { Address = user.Address, Name = user.Name, UserId = user.UserId }; return userViewModel; } }
Now get back to a GetBy method and Edit it like this:
public UserViewModel GetBy(Guid userId) { var users = _userRepository.GetById(userId); var userView = users.ConvertToUserView(); return userView; }
Now we have mapped the User Model to UserViewModel, But it is Not a good way in all cases, AutoMapper could make this more fluently. Get Automapper and reference it to your project and following method to Mapping class that you created before:
public static IEnumerable<UserViewModel> ConvertToUserViewList(this IEnumerable<User> users) { return Mapper.Map<IEnumerable<User>, IEnumerable<UserViewModel>>(users); }
Now refer to UserService class and complete the GetAllUser()
public IEnumerable<UserViewModel> GetAllUser() { var users = _userRepository.GetAll(); var userView = users.ConvertToUserViewList(); return userView; }
And finally, add a class to configure the Automapper
public class AutoMapperConfiguration { public static void ConfigureAutoMapper() { Mapper.CreateMap<User, UserViewModel>(); Mapper.CreateMap<UserViewModel, User>(); } }
Be aware that you should mention this method in Global.asax file of MVC in application_start method
//Service Automapper AutoMapperConfiguration.ConfigureAutoMapper();
And there is Another way to get the same result, create a method in Mapping with this definition :
public static void SetupUserMapping() { Mapper.CreateMap<User, UserViewModel>(); }
And go to the UserService and implement the GetBy() in another form:
public UserViewModel GetBy(Guid userId) { Mapping.SetupUserMapping(); var user = _userRepository.GetById(userId); var userViewModel = Mapper.Map<User, UserViewModel>(user); return userViewModel; }
Both of the above implementation map the Model to ViewModel but first one is recommended. Simply, this method maps the Model to ViewModel and also to map the ViewModel to Model. in this example we can have :
public static User ConvertToModel(this UserViewModel userViewModel) { return Mapper.Map<UserViewModel, User>(userViewModel); }
So in the above cases, members of User and UserViewModel are same, right? For example, we have UserId, Name, Address both in User and UserViewModel, suppose a condition that we have these members in different Name, None of above implementation for methods won't work, you can test it! For example, change the UserViewModel class like this :
public class UserViewModel { public Guid UserId { get; set; } public string Name { get; set; } public string FullAddress { get; set; } }
Now, in this case, we should do like this with Automapper :
public static void SetUpMapping() { Mapper.CreateMap<User, UserViewModel>() .ForMember(destination => destination.FullAddress, options => options.MapFrom(source => source.Address)); }
And again in UserService :
public UserViewModel GetBy(Guid userId) { Mapping.SetUpMapping(); var user = _userRepository.GetById(userId); var userViewModel = Mapper.Map<User, UserViewModel>(user); return userViewModel; }
Or you can create them in one method :
public static UserViewModel ConvertToUserViewModel(this User user) { Mapper.CreateMap<User,UserViewModel>() .ForMember(destination => destination.FullAddress, options => options.MapFrom(source => source.Address)); return Mapper.Map<User, UserViewModel>(user); }
And let's consider another condition, look at this class
public class Profile { public int Id { get; set; } public string Name { get; set; } public string PhoneNumber { get; set; } public string Education { get; set; } }
And ViewModel Class
public class ProfileViewModel { public string Name { get; set; } public string PhoneNumber { get; set; } }
To convert these kinds of classes you don’t need to do anything else but convert it in regular form as you see in above example, Automapper will handle it:
public static Profile ConvertToViewModel(this ProfileViewModel profileViewModel) { return Mapper.Map<ProfileViewModel, Profile>(profileViewModel); }
That's it!
Category: Software