我有一个AutoMapper
当前依赖于UrlHelper
以下映射的配置文件:
CreateMap<Post, OpenGraphModel>().ForMember(
m => m.Title,
x => x.MapFrom(p => p.Link.Title)
).ForMember(
m => m.Description,
x => x.MapFrom(p => p.Link.Description)
).ForMember(
m => m.Image,
x => x.MapFrom(p => p.Link.Picture)
).ForMember(
m => m.Url,
x => x.MapFrom(p => urlHelper.RouteUrl("PostShortcut", new { id = p.Id }, "http"))
);
这很好,直到我想AutoMapper
在 Web 请求之外的上下文中重用我的个人资料。
我可以为此想到三个解决方案,但没有一个能真正说服我(没有特定的顺序):
从映射配置文件中完全删除
UrlHelper
依赖项。在我看来,
这意味着我现在必须手动映射 的Url
属性OpenGraphModel
,这违背了使用的目的。AutoMapper
我喜欢我的映射器能够在目标对象中设置我需要的所有属性。从非 Web 上下文中删除此映射配置文件,因为非 Web 请求上下文不应该直接映射到视图模型。
为了实现这一点,我必须让我的IMapper
实例是瞬态的,每个 Web 请求(或线程),而不是单例,这会引入我不想引入的额外开销。第三种选择是不在
IMapper
非 Web 请求上下文(即作业)上使用实现,但这似乎几乎不可能,因为我正在重用最终需要我使用映射器的组件。
我想拥有两个单例映射器将是最有意义的一个(根据上下文选择配置文件),但我不知道我应该如何做到这一点,这是我的 AutoMapper 安装程序的当前形式:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using AutoMapper;
using AutoMapper.Mappers;
using Castle.MicroKernel;
using Castle.MicroKernel.Registration;
using Castle.MicroKernel.SubSystems.Configuration;
using Castle.Windsor;
namespace Common
{
internal sealed class AutoMapperInstaller : IWindsorInstaller
{
private readonly Type[] profileTypes;
public AutoMapperInstaller(params Type[] profileTypes)
{
if (profileTypes == null)
{
throw new ArgumentNullException("profileTypes");
}
this.profileTypes = profileTypes;
}
public void Install(IWindsorContainer container, IConfigurationStore store)
{
IEnumerable<Assembly> assemblies = profileTypes.Select(t => t.Assembly).ToList();
foreach (Assembly assembly in assemblies)
{
container.Register(
AllTypes
.FromAssembly(assembly)
.BasedOn(typeof (ITypeConverter<,>))
.WithServiceSelf()
);
}
foreach (Assembly assembly in assemblies)
{
container.Register(
Classes
.FromAssembly(assembly)
.BasedOn<Profile>()
.LifestyleTransient()
);
}
container.Register(
Component
.For<ITypeMapFactory>()
.ImplementedBy<TypeMapFactory>()
.LifestyleTransient()
);
container.Register(
Component
.For<IConfiguration, IConfigurationProvider>()
.UsingFactoryMethod(InstanceConfigurationStore)
.LifestyleTransient()
);
container.Register(
Component
.For<IMappingEngine>()
.ImplementedBy<MappingEngine>()
.LifestyleTransient()
);
container.Register(
Component
.For<IMapper>()
.ImplementedBy<Mapper>()
.DynamicParameters(
(k, parameters) => parameters["profileTypes"] = profileTypes
)
.LifestyleSingleton()
);
}
private ConfigurationStore InstanceConfigurationStore(IKernel kernel)
{
ITypeMapFactory typeMapFactory = kernel.Resolve<ITypeMapFactory>();
IEnumerable<IObjectMapper> mappers = MapperRegistry.AllMappers();
return new ConfigurationStore(typeMapFactory, mappers);
}
}
}