문제

도메인 모델, MVC 웹 응용 프로그램 및 단위 테스트 용 어셈블리가있는 현재 프로젝트. 모든 어셈블리가 동일한 구성을 참조하도록 Automapper 구성을 설정하려면 어떻게해야합니까?

웹 앱의 Global.asax에 항목을 넣을 수 있다고 생각하지만 단위 테스트에서 어떻게 사용할 수 있습니까? 또한 구성이 global.asax 인 경우 도메인 모델이 맵을 선택합니까?

많은 감사,

Kevdog.

도움이 되었습니까?

해결책

우리가하는 일은 Bootstrapper와 같은 정적 클래스를 만들고 초기화 코드를 정적 메소드에 넣는 것입니다. 우리는 프로필을하고 있으므로 거기에는 많이 보이지 않습니다. Global.asax는 스타트 업에서 도메인이 사용하여 (구성이 싱글 톤이기 때문에) 사용합니다. 설정에서 bootstrapper.configure ()를 호출 해야하는 단위 테스트.

우리가하는 마지막 한 가지는 부트 스트랩퍼에 깃발을 유지하고 구성 할 때 true로 설정하는 것입니다. 이렇게하면 구성은 AppDomain 당 한 번만 실행됩니다. 이는 Global.asax (Application_Start)의 시작과 단위 테스트를 실행할 때 한 번을 의미합니다.

HTH

다른 팁

또한 Bootstrapper를 사용하여 이러한 종류의 시작 작업을 처리합니다. 사실, 나는 그렇게 미쳤 기 때문에 부트 스트랩 퍼 체인을 사용합니다. Automapper-Wise, 우리는 AutomappingBuddy 클래스를 만들고 속성으로 장식하는 것이 더 깨끗하다는 것을 알았습니다. 그런 다음 약간의 반사 통화를 통해 매퍼를 연결합니다 (싸지 않지만 한 번만 발사 할 때만 발사). 이 솔루션은 1200 개 이상의 라인 파일의 841 행에서 Automapper 문제를 발견 한 후에 발견되었습니다.


나는 코드를 게시하는 것에 대해 생각했지만 실제로 그것을 Purdy라고 부를 수는 없습니다. 어쨌든 여기에 간다 :

먼저, 자동 캡처 버드에 대한 간단한 인터페이스 :

public interface IAutoMappingBuddy
{
    void CreateMaps();
}

둘째, 접착제를 제공하기위한 작은 속성 :

public class AutoMappingBuddyAttribute : Attribute
{
    public Type MappingBuddy { get; private set; }

    public AutoMappingBuddyAttribute(Type mappingBuddyType)
    {
        if (mappingBuddyType == null) throw new ArgumentNullException("mappingBuddyType");
        MappingBuddy = mappingBuddyType;
    }

    public IAutoMappingBuddy CreateBuddy()
    {
        ConstructorInfo ci = MappingBuddy.GetConstructor(new Type[0]);
        if (ci == null)
        {
            throw new ArgumentOutOfRangeException("mappingBuddyType", string.Format("{0} does not have a parameterless constructor."));
        }
        object obj = ci.Invoke(new object[0]);
        return obj as IAutoMappingBuddy;
    }
}

셋째, 자동 캡처 엔진. 마법이 일어나는 곳입니다.

public static class AutoMappingEngine
{
    public static void CreateMappings(Assembly a)
    {
        Dictionary<Type, IAutoMappingBuddy> mappingDictionary = GetMappingDictionary(a);
        foreach (Type t in a.GetTypes())
        {
            var amba =
                t.GetCustomAttributes(typeof (AutoMappingBuddyAttribute), true).OfType<AutoMappingBuddyAttribute>().
                    FirstOrDefault();
            if (amba!= null && !mappingDictionary.ContainsKey(amba.MappingBuddy))
            {
                mappingDictionary.Add(amba.MappingBuddy, amba.CreateBuddy());
            }
        }
        foreach (IAutoMappingBuddy mappingBuddy in mappingDictionary.Values)
        {
            mappingBuddy.CreateMaps();
        }
    }

    private static Dictionary<Type, IAutoMappingBuddy> GetMappingDictionary(Assembly a)
    {
        if (!assemblyMappings.ContainsKey(a))
        {
            assemblyMappings.Add(a, new Dictionary<Type, IAutoMappingBuddy>());
        }
        return assemblyMappings[a];
    }

    private static Dictionary<Assembly, Dictionary<Type, IAutoMappingBuddy>> assemblyMappings = new Dictionary<Assembly, Dictionary<Type, IAutoMappingBuddy>>();
}

한 시간 정도 만에 함께 때리는데, 아마도 그곳에 도착하는 더 우아한 방법이있을 것입니다.

위의 코드를 시도했지만 작동 할 수 없었습니다. 다음과 같이 약간 수정했습니다. 남은 일은 Global.asax의 부트 스트랩퍼를 통해 호출하는 것입니다. 도움이 되었기를 바랍니다.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

using AutoMapper;

namespace Automapping
{
    public class AutoMappingTypePairing
    {
        public Type SourceType { get; set; }
        public Type DestinationType { get; set; }
    }

    public class AutoMappingAttribute : Attribute 
    {
        public Type SourceType { get; private set; }

        public AutoMappingAttribute(Type sourceType)
        {
            if (sourceType == null) throw new ArgumentNullException("sourceType");
            SourceType = sourceType; 
        }
    }

    public static class AutoMappingEngine
    {
        public static void CreateMappings(Assembly a)
        {
            IList<AutoMappingTypePairing> autoMappingTypePairingList = new List<AutoMappingTypePairing>();

            foreach (Type t in a.GetTypes())
            {
                var amba = t.GetCustomAttributes(typeof(AutoMappingAttribute), true).OfType<AutoMappingAttribute>().FirstOrDefault();

                if (amba != null)
                {
                    autoMappingTypePairingList.Add(new AutoMappingTypePairing{ SourceType = amba.SourceType, DestinationType = t});
                }
            } 

            foreach (AutoMappingTypePairing mappingPair in autoMappingTypePairingList) 
            {
                Mapper.CreateMap(mappingPair.SourceType, mappingPair.DestinationType);
            }
        }
    }
}

그리고 나는 이와 같이 그것을 사용하여 소스를 대상 페어링과 연결합니다.

[AutoMapping(typeof(Cms_Schema))]
public class Schema : ISchema
{
    public Int32 SchemaId { get; set; }
    public String SchemaName { get; set; }
    public Guid ApplicationId { get; set; }
}

그런 다음 매핑을 자동으로 만들려면 다음을 수행합니다.

        Assembly assembly = Assembly.GetAssembly(typeof([ENTER NAME OF A TYPE FROM YOUR ASSEMBLY HERE]));

        AutoMappingEngine.CreateMappings(assembly);

Automapper Createmap 호출을 내보기 모델 옆에 사는 수업으로 옮겼습니다. IAUTOMAPPERREGISTRAR 인터페이스를 구현합니다. 반사를 사용하여 IAUTOMAPPERREGISTRAR 구현을 찾고 인스턴스를 작성하고 등록을 추가합니다.

인터페이스는 다음과 같습니다.

public interface IAutoMapperRegistrar
{
    void RegisterMaps();
}

인터페이스의 구현은 다음과 같습니다.

public class EventLogRowMaps : IAutoMapperRegistrar
{
    public void RegisterMaps()
    {
        Mapper.CreateMap<HistoryEntry, EventLogRow>()
            .ConstructUsing(he => new EventLogRow(he.Id))
            .ForMember(m => m.EventName, o => o.MapFrom(e => e.Description))
            .ForMember(m => m.UserName, o => o.MapFrom(e => e.ExecutedBy.Username))
            .ForMember(m => m.DateExecuted, o => o.MapFrom(e => string.Format("{0}", e.DateExecuted.ToShortDateString())));
    }
}

다음은 내 응용 프로그램에서 등록을 수행하는 코드입니다.

foreach (Type foundType in Assembly.GetAssembly(typeof(ISaveableModel)).GetTypes())
{
    if(foundType.GetInterfaces().Any(i => i == typeof(IAutoMapperRegistrar)))
    {
        var constructor = foundType.GetConstructor(Type.EmptyTypes);
        if (constructor == null) throw new ArgumentException("We assume all IAutoMapperRegistrar classes have empty constructors.");
        ((IAutoMapperRegistrar)constructor.Invoke(null)).RegisterMaps();
    }
}

나는 그것이 적절하고 적어도 약간 논리적이라고 생각합니다. 그들은 그런 식으로 따라 가기가 훨씬 쉽습니다. 하나의 거대한 부트 스트랩 방법으로 수백 개의 등록을하기 전에 엉덩이에 통증이되기 시작했습니다.

생각?

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top