AutoMapper – Model/ViewModel mapping and validation

Published by

on

The goal of this post is to implement a base class to map and initialize view models using the domain object. This base class should make not only the mapping between the model and the view model but also the validation of the view model using the model annotations.

Each requirement will be implemented in two different base classes, the validation class will inherit from the mapping one as the domain object is needed to validate the view model. It makes sense to split the logic to keep the code cleaner and also to be able to use only the mapping functionality in case that we don’t need the validation.

Result

When this class is implemented we can implement our view models like this:

public class ItemViewModel : BaseEntityMapperViewModel<ItemViewModelItem>
{
    public int Id { getset; }
    public string Name { getset; }
}

The Model

public class Item
{
    [Key]
    public int Id { getset; }
 
    [MaxLength(200)] 
    [Index(IsUnique = true)]
    public string Name { getset; }
}

Sample of usage:

ViewModel – Model

My WebAPI controllers send and receive to the client a view model instance, when a instance needs to be updated in database it needs to be mapped to the domain first. This is because my domain services know nothing about view models:

// Update item
public void Put([FromBody]ItemViewModel updatedItem)
{
    if (!_itemsService.Update(updatedItem.MapToEntity()))
    {
        throw new HttpResponseException(HttpStatusCode.NotFound);
    }
}

Model – ViewModel

When a WebAPI need to load a instance from database and send it to the client, it loads a domain instance that needs to be mapped to a view model:

// Read item by id
public ItemViewModel Get(int id)
{
    var item = _itemsService.Get(id);
    if (item == null)
    {
        throw new HttpResponseException(HttpStatusCode.NotFound);
    }
    return ItemViewModel.MapFromEntity(item);
}

Implementation

For the mapping class we will use AutoMapper.

Microsoft .NET uses the interface “IValidableObject” for validation. The “ValidatableViewModel” base class will implement this interface. The “Validate” method of this interface will map the view model to the domain object and will returns its validation result.

ViewModel to Model: Map the base view model to the derived view model and the derived model to the domain.

BaseViewModel –> DerivedViewModel –> Model

Model to ViewModel: Static class to create an instance using the model.

Model –> DerivedViewModel

This is the class diagram:

image

BaseEntityMapperViewModel class:

using AutoMapper;
 
namespace Utils.Web
{
    /// <summary>
    /// Allows to map a ViewModel to/from a Domain Entity.
    /// </summary>
    /// <typeparam name="TViewModel">Type of the view model</typeparam>
    /// <typeparam name="TEntity">Type of the entity</typeparam>
    public abstract class BaseEntityMapperViewModel<TViewModel, TEntity>
        where TEntity : class
        where TViewModel : class
    {
        /// <summary>
        /// Initializes the <see cref="BaseEntityMapperViewModel{TViewModel,TEntity}"/> class.
        /// </summary>
        static BaseEntityMapperViewModel()
        {
            // Define the default mapping, 
            // custom configuration can be also defined and will be merged with this one
            Mapper.CreateMap<TViewModel, TEntity>();
            Mapper.CreateMap<TEntity, TViewModel>();
        }
 
        /// <summary>
        /// Maps the specified view model to a entity object.
        /// </summary>
        public TEntity MapToEntity()
        {
            // Map the derived class to the represented view model
            return Mapper.Map<TEntity>(CastToDerivedClass(this));
        }
 
        /// <summary>
        /// Maps a entity to a view model instance.
        /// </summary>
        public static TViewModel MapFromEntity(TEntity model)
        {
            return Mapper.Map<TViewModel>(model);
        }
 
        #region Private
 
        /// <summary>
        /// Gets the derived class.
        /// </summary>
        private static TViewModel CastToDerivedClass(BaseEntityMapperViewModel<TViewModel, TEntity> baseInstance)
        {
            return Mapper.Map<TViewModel>(baseInstance);
        }
 
        #endregion
    }
}

The base class configures Automapper with the default mapping configuration.

BaseValidatableViewModel class:

using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
 
namespace Utils.Web
{
    public abstract class BaseValidatableViewModel<TViewModel, TEntity> : BaseEntityMapperViewModel<TViewModel, TEntity>, IValidatableObject
        where TEntity : class 
        where TViewModel : class
    {
        /// <summary>
        /// Determines whether the mapped entity is valid.
        /// </summary>
        /// <param name="validationContext">The validation context.</param>
        /// <returns>
        /// A collection that holds failed-validation information.
        /// </returns>
        public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
        {
            var modelErrors = new List<ValidationResult>();
 
            // Get the model to validate
            TEntity entity = this.MapToEntity();
 
            // Create a validation context with the model as instance
            var modelValidationContext = new ValidationContext(entity);
 
            // Validate
            Validator.TryValidateObject(entity, modelValidationContext, modelErrors, validateAllProperties: true);
 
            return modelErrors;
        }
    }
}

I am using this class in WebAPI controllers and works very good. If you use ASP MVC I would recommend you to use only the mapping base class. If you add the validation properties to the view model you get the support of Razor to generate client side validation.

3 responses to “AutoMapper – Model/ViewModel mapping and validation”

  1. Farhan Rafiq Avatar
    Farhan Rafiq

    Hi Juan,

    One thing to ask, how can we do mapping in case of intialization of List becuase in this case there is exception saying that missing mapping between ItemViewModel and EntityModel..

    Like

  2. Juan Carlos Sánchez Avatar

    Hi Farhan, sorry for the late response, you need to define the AutoMapper mapping for the list.

    Like

  3. Scott Avatar
    Scott

    This got me off the ground with AutoMapper, thank Juan.

    AutoMapper 4.2 no longer supported the static Mapper class so a very minor revision was needed for that version:

    public abstract class BaseEntityMapperViewModel
    where TEntity : class
    where TViewModel : class
    {
    private static IMapper _mapper;

    static BaseEntityMapperViewModel()
    {
    var config = new MapperConfiguration(cfg => {
    cfg.CreateMap();
    cfg.CreateMap();
    });
    _mapper = config.CreateMapper();
    }

    public TEntity MapToEntity()
    {
    return _mapper.Map(CastToDerivedClass(this));
    }

    public static TViewModel MapFromEntity(TEntity model)
    {
    return _mapper.Map(model);
    }

    private static TViewModel CastToDerivedClass(BaseEntityMapperViewModel baseInstance)
    {
    return _mapper.Map(baseInstance);
    }
    }

    Like

Your feedback is important…

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Blog at WordPress.com.