如何配置AutoMapper一旦每个AppDomain(How to Configure AutoM

2019-07-20 02:47发布

我目前的项目,领域模型,MVC的Web应用程序,和单元测试组件。 我怎样才能建立AutoMapper配置,使所有组件引用相同的配置?

我猜想,我可以把项目在Global.asax中的Web应用程序,但我该如何使用,在单元测试? 此外,如果配置是在Global.asax中,将域模型拿起地图?

非常感谢,

KevDog。

Answer 1:

我们要做的就是创建一个静态类,像引导程序,并把初始化代码的静态方法在那里。 我们正在做的配置文件,这样你就不会看到太多在那里。 Global.asax中会调用在启动时,域将使用它(由于该配置单),并且需要调用BootStrapper.Configure()在其设置的单元测试。

我们做的最后一件事是在引导程序保持一个标志周围,并将其设置为true,当我们配置。 这样一来,配置只执行每个AppDomain一次。 这意味着一旦在Global.asax中(的Application_Start)的启动,一旦当我们运行单元测试。

HTH



Answer 2:

我也用一个引导程序来处理这类的启动任务的事情。 其实,我用bootstrappers链,因为我疯狂的喜欢这一点。 Automapper明智的,我们发现这是很多清洁做一些AutoMappingBuddy类和与属性进行装饰。 然后,我们连线了通过一些反射调用映射器(不便宜,但他们只在一开始走火一次)。 之后我们得了病在1200+行文件的841行找到一个AutoMapper问题,该解决方案被发现。


我想到了张贴的代码,但我真的不能称呼它珀迪。 总之,这里有云:

首先,一个简单的接口,为AutoMappingBuddies:

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

三,AutoMappingEngine。 它的神奇在哪里发生的情况:

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

有点拼凑在一小时左右,大概有更优雅的方式到那里。



Answer 3:

我想上面的代码,但不能让它开始工作。 我修改了它一点点,如下所示。 我认为,所有剩下要做的就是通过从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);


Answer 4:

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

这里是执行我的Application_Start的注册代码:

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

我想,这是适当的,至少有点逻辑; 他们是一个更容易遵循的方式。 之前,我有几百个注册的一个巨大的引导方法,并且已开始成为一个痛苦的屁股。

思考?



文章来源: How to Configure AutoMapper Once Per AppDomain