Skip to content

AutoMapper

Auto Mapper and automatic wiring tricks

AutoMapper is my web development drug at the moment. I feel that I am constantly taking objects that are practically identical and mapping them to others. Automapper is an obvious answer to this but I still don’t want to have to take the time to manage disconnected objects. What I would rather do (and did) was create a way to map the objects to one another that is attached to the class definition itself. To accomplish this, I create a custom attribute to mark both classes and properties.

The custom attribute is defined as:


/// <summary>
/// Class MappedDTOAttribute. This class cannot be inherited.
/// </summary>
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)]
public sealed class MappedDTOAttribute : Attribute
{
    /// <summary>
    /// The _mapped type
    /// </summary>
    readonly Type _mappedType;

    /// <summary>
    /// Initializes a new instance of the <see cref="MappedDTOAttribute"/> class.
    /// </summary>
    /// <param name="mappedType">Type to be mapped.</param>
    public MappedDTOAttribute(Type mappedType)
    {
        this._mappedType = mappedType;
    }

    /// <summary>
    /// Gets the Type to be mapped.
    /// </summary>
    /// <value>The Type to be mapped.</value>
    public Type MappedType
    {
        get { return _mappedType; }
    }

    /// <summary>
    /// Gets or sets the primary identifier for this and the mapped type.
    /// </summary>
    /// <value>The primary identifier for this and the mapped type.</value>
    public string Key { get; set; }
}

The AutoMapper magic is done in a static utility that is invoked after ASP.NET MVC has loaded all relevant assembiles:


public static class Utilities
{
    public static void AutoMapperMagic()
    {

        // This get all types from all Assemblies in the Current Application Domain that has the ODataEntityAttribute
        var attributedTypes = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes().Where(x => x.GetCustomAttribute<MappedDTOAttribute>() != null));

        //looped through the types and add plug them into automapper
        foreach (var type in attributedTypes)
        {
            //get the types the type will map to
            var mappedTypes = type.GetCustomAttributes<MappedDTOAttribute>().Select(x => x.MappedType);

            //for each type map that type to the type
            foreach (var mappedType in mappedTypes)
            {
                var toDomainTypeConf = AutoMapper.Mapper.CreateMap(type, mappedType);
                var toMappedTypeConf = AutoMapper.Mapper.CreateMap(mappedType, type);

                //get the properties that are a mapped type
                var propertiesToIgnore = type.GetProperties().Where(x => attributedTypes.Any(y => y == x.PropertyType));

                //ignore those properties in the map, if there are any
                //(this is to prevent infinite recursion of foreign keys
                if (propertiesToIgnore.Any())
                {
                    foreach (var propertyToIgnore in propertiesToIgnore)
                    {
                        toDomainTypeConf.ForMember(propertyToIgnore.Name, x => x.Ignore());
                        toMappedTypeConf.ForMember(propertyToIgnore.Name, x => x.Ignore());
                    }
                }
            }
        }
    }
}

Now, with this code. Any type mapped with a MappedTypeAttribute will be picked up by AutoMapper and configured appropriately.

Twitter Auto Publish Powered By : XYZScripts.com