現在、次のマッピングに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 リクエスト以外のコンテキストで自分のプロファイルを再利用するまでは、これで問題ありませんでした。
これには 3 つの解決策が考えられますが、どれも本当に納得できません (順不同)。
UrlHelper
マッピング プロファイルから依存関係を完全に削除します。
これは、私の意見では、のUrl
プロパティを手動でマッピングする必要があることを意味します。目的のオブジェクトに必要なすべてのプロパティを設定できるマッパーが気に入っています。OpenGraphModel
AutoMapper
いずれにせよ、非 Web 要求コンテキストはビュー モデルに直接マッピングされるべきではないため、非 Web コンテキストからこのマッピング プロファイルを削除します。
これを実現するには、IMapper
インスタンスをシングルトンではなく、Web リクエスト (またはスレッド) ごとに一時的に作成する必要があります。これにより、導入したくない追加のオーバーヘッドが発生します。3 番目のオプションは、
IMapper
Web 以外のリクエスト コンテキスト (つまり、ジョブ) で実装を使用しないことですが、マッパーを使用する必要があるコンポーネントを再利用しているため、これはほとんど問題外に思えます。
2 つのシングルトン マッパーを持つことが最も理にかなっていると思います(コンテキストに基づいてプロファイルを選択します)。
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);
}
}
}