net microsoft for extensions dependencyinjection dependency-injection automapper

dependency-injection - microsoft - profile automapper



Automapper junto con inyección de dependencia (4)

Actualmente tengo el siguiente mapeo:

Mapper.CreateMap<Journal, JournalDto>();

Ahora, el Journal contiene un miembro llamado RefTypeID , cuyo valor correspondiente existe en otra tabla en la base de datos; Para buscar este valor, tengo un servicio que maneja una simple solicitud de int -> string . La configuración de automapper actualmente ocurre en una clase estática al inicio del programa. ¿Está bien mover el código de mapeo a una clase que se inyecta en mi contenedor DI o hay una mejor manera?



Así es como lo resolví:

He definido una interfaz IMappingCreator :

public interface IMappingCreator { void CreateMappings(); }

Seguí adelante e implementé una clase con esa interfaz (estoy usando MEF como contenedor DI, de ahí provienen los atributos) que se coloca en el contenedor DI como IMappingCreator :

[Export(typeof(IMappingCreator))] public class Mapping : IMappingCreator { private readonly IRefTypesLookup iRefTypesLookup; [ImportingConstructor] public Mapping(IRefTypesLookup rtl) { iRefTypesLookup = rtl; } public void CreateMappings() { Mapper.CreateMap<Journal, DisplayJournal>().AfterMap((j, dj) => dj.RefTypeName = iRefTypesLookup.Lookup(j.RefTypeID)); } }

Finalmente, en el inicio de mi aplicación, recupero todas las instancias de esa interfaz en el contenedor y CreateMappings método CreateMappings en ellas:

var mappings = container.GetExportedValues<IMappingCreator>(); foreach (IMappingCreator mc in mappings) { mc.CreateMappings(); }

Esto hace que la configuración inicial sea bastante fácil, ya que toda la creación se realiza en un solo lugar, y puede tener tantos creadores de mapeo como desee (sin embargo, debe mantenerlos al mínimo, tal vez una vez por proyecto o algo así, obteniendo todos los servicios necesarios) para mapear los tipos específicos en ese proyecto).



Una mejor manera es utilizar un sistema de resolución de clientes. La configuración de la asignación está pensada para ser estática, por lo que las resoluciones personalizadas están diseñadas para proporcionar la asignación de un solo miembro:

Mapper.Initialize(cfg => { cfg.ConstructServicesUsing(type => WhateverMefUsesToGetInstances.GetInstance(type)); cfg.CreateMap<Journal, DisplayJournal>() .ForMember(dest => dest.RefTypeName, opt => opt.ResolveUsing<RefTypeNameResolver>()); });

Entonces su resolutor se convierte en:

[Export(typeof(IRefTypeNameResolver))] public class RefTypeNameResolver : ValueResolver<Journal, string>, IRefTypeNameResolver { private readonly IRefTypesLookup iRefTypesLookup; [ImportingConstructor] public RefTypeNameResolver (IRefTypesLookup rtl) { iRefTypesLookup = rtl; } protected override string ResolveCore(Journal source) { return iRefTypesLookup.Lookup(source.RefTypeID); } }

La configuración debe ejecutarse una vez, razón por la cual la API de configuración proporciona enlaces a la API de ejecución (convertidores de tipo, resolvedores de valor, etc.)