Mapper para Entidades [C#]

  • 0 Respuestas
  • 2743 Vistas

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado xxneeco83xx

  • *
  • Underc0der
  • Mensajes: 46
  • Actividad:
    0%
  • Reputación 0
  • ASM/C/C++/VB/Delphi
  • Skype: nico.buzzi
    • Ver Perfil
    • Email

Mapper para Entidades [C#]

  • en: Julio 29, 2016, 07:48:40 pm
Que tal ! llevo mucho tiempo desde la ultima vez que ingrese aquí y compartí algo, con el tema de que ocurrieron muchos cambios en estos últimos meses y demás, se hizo dificil.
Les dejo un Mapper que desarrolle hace unos días atrás que es una alternativa a el Famoso "AutoMapper" que a mi recomendación es preferible que no se le use, ya que es demaciado lento.
Este codigo que adjuntare junto con su ejemplo de uso, pasara un object con sus navigations properties así mismo sean listas, a DTO o a ViewModel.

Código: (csharp) [Seleccionar]
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;

namespace ConsoleApplication1
{
    public class MapperConfiguration
    {
        public string Name { get; set; }
        public IList<string> AssemblyList { get; set; }
        public List<Assembly> Classes { get; set; }
    }
   
    public static class Mapper
    {
        private static MapperConfiguration _mapperConfiguration = new MapperConfiguration { Name = "DTO" };

        public static void ConfigureMapper(MapperConfiguration mapperConfiguration)
        {
            //_mapperConfiguration.Name = mapperConfiguration.Name;
            _mapperConfiguration = mapperConfiguration;

            if ( mapperConfiguration.AssemblyList != null)
            {
                foreach(var item in mapperConfiguration.AssemblyList)
                {
                    var assemblyTempList = Assembly.ReflectionOnlyLoad(item);
                    _mapperConfiguration.Classes.Add(assemblyTempList);
                }
               
            }
        }

        #region Mapper con configuracion

        public static U MapProperty<T,U>(this T source, IDictionary<string,string> configurationMapper)
            where T : class, new()
            where U : class, new()
        {
            if ( source == null || configurationMapper == null)
            {
                return default(U);
            }

            /*Obtenemos las properties del object source*/
            var sourceProperties = source.GetType().GetProperties();

            var destinyInstance = Activator.CreateInstance(typeof(U));
            var destinyProperties = destinyInstance.GetType().GetProperties();

            foreach(var i in sourceProperties)
            {
                //Buscamos si la property que quiere copiar tiene source
                var firstFind = configurationMapper.FirstOrDefault(m => m.Key.Contains(i.Name));
                if (string.IsNullOrEmpty(firstFind.Key) || string.IsNullOrEmpty(firstFind.Value))
                    continue;

                var secondFind = destinyProperties.FirstOrDefault(m => m.Name.Contains(firstFind.Value));
                if ( secondFind == null)
                {
                    continue;
                }

                if ( i.Name.Contains("Collection"))
                {

                }

                secondFind.SetValue(destinyInstance, i.GetValue(source));

            }

            return (U)destinyInstance;
        }

        #endregion

        #region Formula 1

        /*Metodo para mapear simples objects*/
        public static dynamic Map<T>(this T source)
            where T : class, new()
        {
            //Check for source
            if (source == null )
                return null;

            //Donde almacenaremos el tipo de destino
            Type destinyType = null;

            //Obtenemos todas las clases
            var classList = Assembly.GetExecutingAssembly().GetTypes();

            //Obtenemos las properties del source
            var propertiesSource = source.GetType().GetProperties();

            //Si no podemos obtener clases o properties
            if ( propertiesSource == null || classList == null )
            {
                return new Exception("Error al obtener clases o properties desde el assembly");
            }

            if (source.GetType().ToString().Contains("Collection"))
            {
                if (source.GetType().Name.Contains("ViewModel") || source.GetType().Name.Contains("DTO") || source.GetType().Name.Contains(_mapperConfiguration.Name))
                {
                    var firstTest = Regex.Split(propertiesSource.FirstOrDefault().Name, "ViewModel")[0];
                    if (string.IsNullOrEmpty(firstTest))
                    {
                        firstTest = "DTO";
                    }
                    else
                    {
                        firstTest = "ViewModel";
                    }

                    destinyType = classList.FirstOrDefault(
                        m => m.Name.Contains(Regex.Split(propertiesSource.FirstOrDefault().Name,firstTest)[0] + _mapperConfiguration.Name));
                }
                else
                {
                    destinyType = classList.FirstOrDefault(
                        m => m.Name.Contains(propertiesSource.FirstOrDefault().Name + _mapperConfiguration.Name));
                }
            }
            else
            {
                if (source.GetType().Name.Contains("ViewModel") || source.GetType().Name.Contains("DTO") || source.GetType().Name.Contains(_mapperConfiguration.Name))
                {
                    var firstTest = Regex.Split(source.GetType().Name, "ViewModel")[0];
                    if (string.IsNullOrEmpty(firstTest))
                    {
                        firstTest = "DTO";
                    } else
                    {
                        firstTest = "ViewModel";
                    }

                    destinyType = classList.FirstOrDefault(
                        m => m.Name.Contains(Regex.Split(source.GetType().Name,firstTest)[0] + _mapperConfiguration.Name));
                }
                else
                {
                    destinyType = classList.FirstOrDefault(
                        m => m.Name.Contains(source.GetType().Name + _mapperConfiguration.Name));
                }
            }

            try
            {

                //Creamos la instancia del object
                var instance = Activator.CreateInstance(destinyType);

                //Obtenemos las properties del object de destino
                var propertyOfDestiny = instance.GetType().GetProperties();

                foreach (var item in propertyOfDestiny)
                {
                    //Buscamos la property
                    var result = propertiesSource.FirstOrDefault(m => m.Name == item.Name);
                    if (result != null)
                    {
                        //En caso de que no sea un Object de tipo distinto a los nativos de C#
                        if ((!(result).PropertyType.Name.Contains("String")) && (!(result).PropertyType.Name.Contains("Int"))
                            && (!(result).PropertyType.Name.Contains("Bool")) && (!(result).PropertyType.Name.Contains("Float"))
                            && (!(result).PropertyType.Name.Contains("Double")))
                        {
                            //En caso de ser lista
                            if (result.ToString().Contains("Collection"))
                            {
                                Type type = null;

                                if (result.PropertyType.GetGenericArguments().Single().Name.Contains("ViewModel") || result.PropertyType.GetGenericArguments().Single().Name.Contains("DTO") ||
                                    result.PropertyType.GetGenericArguments().Single().Name.Contains(_mapperConfiguration.Name))
                                {
                                    var firstTest = Regex.Split(result.PropertyType.GetGenericArguments().Single().Name, "ViewModel")[0];
                                    if (string.IsNullOrEmpty(firstTest))
                                    {
                                        firstTest = "DTO";
                                    } else
                                    {
                                        firstTest = "ViewModel";
                                    }

                                    type = classList.FirstOrDefault(m => m.FullName.Contains(Regex.Split(result.PropertyType.GetGenericArguments().Single().Name,firstTest)[0] + _mapperConfiguration.Name));
                                }
                                else
                                {
                                    type = classList.FirstOrDefault(m => m.FullName.Contains(result.PropertyType.GetGenericArguments().Single().Name + _mapperConfiguration.Name));
                                }

                                if (type == null)
                                {
                                    continue;
                                }

                                var listInstance = (IList)typeof(List<>).MakeGenericType(type).GetConstructor(Type.EmptyTypes).Invoke(null);

                                item.SetValue(instance, ((ICollection)result.GetValue(source)).MapList());
                            }
                            else
                            {
                                Type type = null;
                                if (result.Name.Contains("ViewModel") || result.Name.Contains("DTO") ||
                                    result.Name.Contains(_mapperConfiguration.Name))
                                {

                                    var firstTest = Regex.Split(result.Name, "ViewModel")[0];
                                    if (string.IsNullOrEmpty(firstTest))
                                    {
                                        firstTest = "DTO";
                                    }
                                    else
                                    {
                                        firstTest = "ViewModel";
                                    }

                                    //En caso de ser un object
                                    type = classList.FirstOrDefault(m => m.FullName.Contains(Regex.Split(result.Name,firstTest)[0] + _mapperConfiguration.Name));
                                }
                                else
                                {
                                    //En caso de ser un object
                                    type = classList.FirstOrDefault(m => m.FullName.Contains(result.Name + _mapperConfiguration.Name));
                                }
                                if (type == null)
                                {
                                    continue;
                                }

                                item.SetValue(instance, result.GetValue(source).Map());
                            }
                        }
                        else
                        {
                            //Property normal
                            item.SetValue(instance, result.GetValue(source));
                        }
                    }
                }

                return instance;

            }
            catch (Exception e)
            {
                return e.Message;
            }

        }

        /*Metodos para mapear listas*/
        public static dynamic MapList<T>(this T source)
            where T : ICollection
        {
            //Check for source
            if (source == null)
                return null;

            if (source.GetType().GetGenericArguments().Count() == 0)
                return null;

            Type destinyType = null;
            bool isCollection = false;

            if (source.GetType().ToString().Contains("Collection"))
            {
                foreach(var i in source)
                {
                    if ( i.GetType().Name.Contains("ViewModel") || i.GetType().Name.Contains("DTO") || i.GetType().Name.Contains(_mapperConfiguration.Name))
                    {
                        var firstTest = Regex.Split(i.GetType().Name, "ViewModel")[0];
                        if (string.IsNullOrEmpty(firstTest))
                        {
                            firstTest = Regex.Split(i.GetType().Name, "DTO")[0];
                        }

                        destinyType = Assembly.GetExecutingAssembly().GetTypes().FirstOrDefault(
                            m => m.Name.Contains(firstTest + _mapperConfiguration.Name));
                    }
                    else
                    {
                        destinyType = Assembly.GetExecutingAssembly().GetTypes().FirstOrDefault(
                            m => m.Name.Contains(i.GetType().Name + _mapperConfiguration.Name));
                    }

                    isCollection = true;

                    break;
                }
            }

            if (!isCollection)
                return new Exception("Este object no es una lista de tipo coleccion");

            var listType = source.GetType().GetGenericArguments().Single();

            //Check if the type of object is or not a collection list.
            if (source.GetType().ToString().Contains("Collection"))
            {
                try
                {
                    dynamic list;

                    //Create instance of list
                    if ( isCollection)
                    {
                        list = (IList)typeof(List<>).MakeGenericType(destinyType).GetConstructor(Type.EmptyTypes).Invoke(null);
                    } else
                    {
                        list = Activator.CreateInstance(destinyType);
                    }

                    //Loop in the list
                    foreach (var i in source)
                    {
                        if (i.GetType().ToString().Contains("Collection"))
                        {
                            var mapped = ((ICollection)i).MapList();

                            foreach (var item in mapped)
                            {
                                ((IList<object>)list).Add(item);
                            }

                        }
                        else
                        {
                            ((IList)list).Add(i.Map());
                        }

                    }

                    return list;
                }
                catch (Exception e)
                {
                    return e.Message;
                }

            }

            return null;
        }

        #endregion

        #region Formula 2

        /*Metodo para mapear simples objects*/
        public static dynamic MapToEntity<T>(this T source)
            where T : class, new()
        {
            //Check for source
            if (source == null)
                return null;

            Type destinyType = null;

            //Obtenemos todas las clases
            var classList = Assembly.GetExecutingAssembly().GetTypes();

            //Obtenemos las properties del source
            var propertiesSource = source.GetType().GetProperties();

            //Si no podemos obtener clases o properties
            if ( propertiesSource == null || classList == null )
            {
                return new Exception("Error al obtener clases o properties desde el assembly");
            }

            if (source.GetType().ToString().Contains("Collection"))
            {
                destinyType = classList.FirstOrDefault(
                    m => m.Name.Contains(Regex.Split(propertiesSource.FirstOrDefault().Name,_mapperConfiguration.Name)[0]));

            }
            else
            {
                destinyType = classList.FirstOrDefault(
                    m => m.Name.Contains(Regex.Split(source.GetType().Name,_mapperConfiguration.Name)[0]));
            }

            try
            {
                //Creamos la instancia del object
                var instance = Activator.CreateInstance(destinyType);

                //Obtenemos las properties del object de destino
                var propertyOfDestiny = instance.GetType().GetProperties();

                foreach (var item in propertyOfDestiny)
                {
                    //Buscamos la property
                    var result = propertiesSource.FirstOrDefault(m => m.Name == item.Name);
                    if (result != null)
                    {
                        //En caso de que no sea un Object de tipo distinto a los nativos de C#
                        if ((!(result).PropertyType.Name.Contains("String")) && (!(result).PropertyType.Name.Contains("Int"))
                            && (!(result).PropertyType.Name.Contains("Bool")) && (!(result).PropertyType.Name.Contains("Float"))
                            && (!(result).PropertyType.Name.Contains("Double")))
                        {
                            //En caso de ser lista
                            if (result.ToString().Contains("Collection"))
                            {
                                var type = classList.FirstOrDefault(m => m.FullName.Contains(Regex.Split(result.PropertyType.GetGenericArguments()
                                    .Single().Name,_mapperConfiguration.Name)[0]));

                                if (type == null)
                                {
                                    continue;
                                }

                                var listInstance = (IList)typeof(List<>).MakeGenericType(type).GetConstructor(Type.EmptyTypes).Invoke(null);

                                item.SetValue(instance, ((ICollection)result.GetValue(source)).MapToEntityList());
                            }
                            else
                            {
                                //En caso de ser un object
                                var type = classList.FirstOrDefault(m => m.FullName.Contains(Regex.Split(result.Name,_mapperConfiguration.Name)[0]));

                                if (type == null)
                                {
                                    continue;
                                }

                                item.SetValue(instance, result.GetValue(source).MapToEntity());
                            }
                        }
                        else
                        {
                            //Property normal
                            item.SetValue(instance, result.GetValue(source));
                        }
                    }
                }

                return instance;

            }
            catch (Exception e)
            {
                return e.Message;
            }

        }

        /*Metodos para mapear listas*/
        public static dynamic MapToEntityList<T>(this T source)
            where T : ICollection
        {

            //Check for source
            if (source == null)
                return null;

            if (source.GetType().GetGenericArguments().Count() == 0)
                return null;

            Type destinyType = null;
            bool isCollection = false;

            if (source.GetType().ToString().Contains("Collection"))
            {
                foreach (var i in source)
                {
                    destinyType = Assembly.GetExecutingAssembly().GetTypes().FirstOrDefault(
                    m => m.Name.Contains(Regex.Split(i.GetType().Name,_mapperConfiguration.Name)[0]));

                    isCollection = true;

                    break;
                }
            }

            if (!isCollection)
                return new Exception("Este object no es una lista de tipo coleccion");

            var listType = source.GetType().GetGenericArguments().Single();

            //Check if the type of object is or not a collection list.
            if (source.GetType().ToString().Contains("Collection"))
            {
                try
                {
                    dynamic list;

                    //Create instance of list
                    if (isCollection)
                    {
                        list = (IList)typeof(List<>).MakeGenericType(destinyType).GetConstructor(Type.EmptyTypes).Invoke(null);
                    }
                    else
                    {
                        list = Activator.CreateInstance(destinyType);
                    }

                    //Loop in the list
                    foreach (var i in source)
                    {
                        if (i.GetType().ToString().Contains("Collection"))
                        {
                            var mapped = ((ICollection)i).MapToEntityList();

                            foreach (var item in mapped)
                            {
                                ((IList<object>)list).Add(item);
                            }

                        }
                        else
                        {
                            ((IList)list).Add(i.MapToEntity());
                        }

                    }

                    return list;
                }
                catch (Exception e)
                {
                    return e.Message;
                }

            }

            return null;
        }

        #endregion
    }
}


Ejemplo de uso

Código: (csharp) [Seleccionar]
using ConsoleApplication1.DTO;
using ConsoleApplication1.Entidades;
using System;
using System.Collections.Generic;

public class Uno
{
    public string Nombre { get; set; }
    public string Apellido { get; set; }

    public void Saludar(string message, string another)
    {
        Console.WriteLine(message + "\n" + another);
        return;
    }
}

public class Dos
{
    public string Name { get; set; }
    public string SurName { get; set; }

    public void Saludar(string message)
    {
        Console.WriteLine(message);
        return;
    }
}

namespace ConsoleApplication1
{
    public static class RemoteCall
    {
        /*
         * Assembly assembly = Assembly.LoadFile("...Assembly1.dll");
         * Type type = assembly.GetType("TestAssembly.Main");
         */
        public static T Instance<T>()
            where T : class, new()
        {
            return (T)Activator.CreateInstance(typeof(T));
        }

        public static T Invoke<T>(string methodName, object[] parameters)
            where T : class, new()
        {
            var classSource = Instance<T>();
            var methods = classSource.GetType().GetMethods();

            foreach(var i in methods)
            {
                if ( i.Name == methodName)
                {
                    i.Invoke(classSource, parameters);
                }
            }

            return default(T);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {

            var objeto = new Usuario
            {
                Id = 1,
                Nombre = "Nicolas",
                Perfil = new List<Perfil>
                {
                    new Perfil
                    {
                        Tipo = "Normal",
                        Entrega = new Entrega
                        {
                            Proveedor = "Nicolas"
                        }
                    },
                    new Perfil
                    {
                        Tipo = "Punchi",
                        Entrega = new Entrega
                        {
                            Proveedor = "Jebus"
                        }
                    }
                }
            };

            //var instanciado = RemoteCall.Instance<Uno>();
            RemoteCall.Invoke<Dos>("Saludar", new object[] { "hola amigos" } );

            var source = new Uno { Nombre = "Nicolas", Apellido = "Buzzi" };

            var dic = new Dictionary<string, string>();

            dic.Add("Nombre", "Name");
            dic.Add("Apellido", "SurName");

            var mapeo = source.MapProperty<Uno,Dos>(dic);

            var listOfObjects = new List<Usuario>();
            listOfObjects.Add(objeto);
            listOfObjects.Add(objeto);

            //Inicializamos el mapper con nuestra configuracion para adaptarla a viewModel
            Mapper.ConfigureMapper(new MapperConfiguration { Name = "ViewModel" });

            /*Convetimos Entidad a DTO*/
            List<UsuarioViewModel> resultadosViewModel = listOfObjects.MapList();

            /*Convertimos los ViewModel a Entidades*/
            List<Usuario> entidadesDeViewModel = resultadosViewModel.MapToEntityList();

           
            //Inicializamos el mapper con nuestra configuracion para adaptarla a DTOS
            Mapper.ConfigureMapper(new MapperConfiguration { Name = "DTO" });

            //Convertimos el resultado de ViewModels a DTO
            List<UsuarioDTO> resultadosDTO = resultadosViewModel.MapList();

            //Convetimos los DTO a entidad
            var resultEntity = resultadosDTO.MapToEntityList();

            Console.BackgroundColor = ConsoleColor.Black;
            Console.ForegroundColor = ConsoleColor.Green;

            Console.WriteLine("Todo correcto");
            Console.ReadLine();

        }
    }
}


Les dejare el link por si quieren descargarse el proyecto completo.
https://github.com/xxneeco83xx/Mapper

Espero que les sea de ayuda, y cualquier duda, sugerencia o comentario, estoy a la espera.
Saludos.
« Última modificación: Julio 30, 2016, 12:51:12 am por ANTRAX »
El arte de crear malware, es algo que solo pocos entienden!