代码之家  ›  专栏  ›  技术社区  ›  KevDog

如何为每个AppDomain配置一次automapper

  •  19
  • KevDog  · 技术社区  · 16 年前

    我当前的项目包含域模型、MVC Web应用程序和单元测试的程序集。如何设置automapper配置,以便所有程序集引用相同的配置?

    我想我可以把Gasal.Axax中的项目放到Web应用程序中,但如何在单元测试中使用呢?另外,如果配置在global.asax中,域模型会得到映射吗?

    多谢,

    KevDog。

    4 回复  |  直到 13 年前
        1
  •  28
  •   Jimmy Bogard    16 年前

    我们要做的是创建一个静态类,类似于引导程序,并将初始化代码放在静态方法中。我们在做个人资料,所以你看不到太多。global.asax将在启动时调用它,域将使用它(因为配置是singleton),并且需要它的单元测试将在其设置中调用bootstrapper.configure()。

    最后一件事是在引导程序上保留一个标志,并在配置时将其设置为true。这样,每个AppDomain配置只执行一次。这意味着在global.asax(application_start)启动时一次,在运行单元测试时一次。

    高温高压

        2
  •  4
  •   Wyatt Barnett    16 年前

    我还使用引导程序来处理这类启动任务。事实上,我使用了一系列的引导程序,因为我像那样疯狂。从automapper的角度来看,我们发现制作一些automappingBuddy类并用一个属性来装饰它们是非常干净的。然后,我们通过一些反射调用连接映射器(不便宜,但它们在开始时只发射一次)。这个解决方案是在我们厌倦了在1200+行文件的第841行中发现automapper问题之后发现的。


    我曾想过要发布代码,但我不能称之为珀迪。不管怎样,这里是:

    首先,自动应用伙伴的简单接口:

    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>>();
    }
    

    大概一个小时左右,我们就可以轻松地到达那里。

        3
  •  4
  •   tschreck    16 年前

    我尝试过上面的代码,但无法使其工作。我修改了一下,如下所示。我想剩下要做的就是通过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);
    
        4
  •  2
  •   Jereme    13 年前

    我一直在将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();
        }
    }
    

    我认为这是适当的,至少有一点逻辑性;它们更容易遵循这种方式。在我用一个巨大的自举方法注册了数百个用户之前,这已经开始让我头疼了。

    思想?

    推荐文章