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?
Aquí está la nueva forma de hacerlo ...
Aunque personalmente agrego las asignaciones automáticas en el controlador, no en el repositorio. De esta manera, puede usar el mismo repositorio para diferentes controladores y tener diferentes asignaciones. Sin embargo, el mismo concepto, simplemente inyecte el IMapper
en el controlador en lugar del repositorio.
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).
Podría tomar una dependencia en IMappingEngine
lugar de usar el Mapper
clases estático.
Hay una buena publicación en el blog al respecto aquí: burlarse de AutoMapper con Dependency Injection
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.)