如何使用 Simple Injector 注册 AutoMapper 4.2.0
How to register AutoMapper 4.2.0 with Simple Injector
已更新至 AutoMapper 4.2.0,并遵循此处提供的迁移指南:https://github.com/AutoMapper/AutoMapper/wiki/Migrating-from-static-API/f4784dac61b91a0df130e252c91a0efd76ff51de#preserving-static-feel。尝试将 StructureMap 页面上的代码转换为简单注入器。有人可以告诉我这段代码在 Simple Injector 中的样子吗?
结构图
public class AutoMapperRegistry : Registry
{
public AutoMapperRegistry()
{
var profiles =
from t in typeof (AutoMapperRegistry).Assembly.GetTypes()
where typeof (Profile).IsAssignableFrom(t)
select (Profile)Activator.CreateInstance(t);
var config = new MapperConfiguration(cfg =>
{
foreach (var profile in profiles)
{
cfg.AddProfile(profile);
}
});
For<MapperConfiguration>().Use(config);
For<IMapper>().Use(ctx => ctx.GetInstance<MapperConfiguration>().CreateMapper(ctx.GetInstance));
}
}
简单的注射器
?
这相当于:
container.RegisterInstance<MapperConfiguration>(config);
container.Register<IMapper>(() => config.CreateMapper(container.GetInstance));
Simple Injector 的 IPackage 接口似乎最接近 StructureMap 的 Registry 类型。这是我使用的包,从 :
构建
using System;
using System.Linq;
using System.Reflection;
//
using AutoMapper;
//
using SimpleInjector;
using SimpleInjector.Packaging;
public class AutoMapperPackage : IPackage
{
public void RegisterServices(Container container)
{
var profiles = Assembly.GetExecutingAssembly()
.GetTypes()
.Where(x => typeof(AutoMapper.Profile).IsAssignableFrom(x));
var config = new MapperConfiguration(cfg =>
{
foreach (var profile in profiles)
{
cfg.AddProfile(Activator.CreateInstance(profile) as AutoMapper.Profile);
}
});
container.RegisterInstance<MapperConfiguration>(config);
container.Register<IMapper>(() => config.CreateMapper(container.GetInstance));
}
}
您需要添加 SimpleInjector.Packaging 包,然后在 bootstrap/configuration 代码中添加对 container.RegisterPackages();
的调用。
从本质上讲,与 StructureMap 唯一真正不同的是最后两行。
为了用不同的 MapperConfiguration 对象映射多个 IMapper,这似乎是一个反复出现的问题,我推荐以下方法,它甚至不需要重构映射器方法调用:
1) 在 IMapper 接口周围创建一个通用包装器。这个包装器可以是一个接口或 Class,但显然最终你必须实现你的包装器,所以我将在下面展示具体的 class。让这个包装器实现(或者继承,如果你选择创建一个接口) IMapper 接口,像这样:
public class ProfileMapper<TProfile> : IMapper where TProfile : Profile
{
private IMapper mapper;
private Profile profile;
public ProfileMapper(TProfile profile)
{
this.profile = profile;
this.mapper = new MapperConfiguration( cfg => cfg.AddProfile( this.profile ) )
.CreateMapper();
}
}
通用参数必须是 "Profile" 的子class,因为您将从该配置文件中获取映射器配置。
2) 在此 class 中,只需将调用重定向到您在构造函数中创建的私有 IMapper 实例,即可实现 IMapper 接口,如下所示:
public TDestination Map<TDestination>(object source)
{
return mapper.Map<TDestination>( source );
}
3) 现在您需要在 Simple Injector 中为您拥有的每个配置文件注册此 ProfileMapper class 的部分关闭实例。为此,您首先获取所有继承自 Profile 的 classes,然后创建这个部分关闭的实例并注册它。有几种方法可以获取所有配置文件 classes,但我选择了这个:
IEnumerable<Type> profileRegistrations =
from type in profileAssembly.GetExportedTypes()
where type.Namespace == "Namespace.Of.My.Profiles"
where type.BaseType.Equals( typeof( Profile ) )
select type;
foreach (Type profileType in profileRegistrations)
{
Container.RegisterSingleton( profileType, profileType );
Type mapperClosedType = typeof( ProfileMapper<> ).MakeGenericType( profileType );
Container.RegisterSingleton( typeof( ProfileMapper<> ), mapperClosedType );
}
此代码首先获取所有继承自配置文件的类型,位于所述命名空间中。然后对于每个配置文件,我用 SimpleInjector 注册它(不是真的必要,因为它们是具体类型,因此可以由容器即时创建),然后我创建一个部分关闭的 ProfileWrapper 实例 class 将当前 Profile 作为通用参数,最后我将关闭的实例注册为 Singleton。这样,您可以创建新的配置文件,而无需手动注册新的包装器。
就是这样。现在,您不再依赖和注入 IMapper,而是将您的 ProfileWrapper 注入您想要使用的配置文件,如下所示:
ProfileMapper<ApplicationProfile> appProfileMapper;
ProfileMapper<MvcProfile> mvcProfileMapper;
ProfileMapper<GuestProfile> guestProfile;
等等。每个 Wrapper 都是使用不同的配置文件使用单独的 MapperConfiguration 创建的。由于包装器实现了 IMapper,因此您的所有映射代码都保持不变。无需重构方法调用,只需重构依赖类型。
如果您创建一个 BaseProfile,只需将 ProfileMapper 中的通用参数更改为仅接受此 BaseProfile 的实例。
已更新至 AutoMapper 4.2.0,并遵循此处提供的迁移指南:https://github.com/AutoMapper/AutoMapper/wiki/Migrating-from-static-API/f4784dac61b91a0df130e252c91a0efd76ff51de#preserving-static-feel。尝试将 StructureMap 页面上的代码转换为简单注入器。有人可以告诉我这段代码在 Simple Injector 中的样子吗?
结构图
public class AutoMapperRegistry : Registry
{
public AutoMapperRegistry()
{
var profiles =
from t in typeof (AutoMapperRegistry).Assembly.GetTypes()
where typeof (Profile).IsAssignableFrom(t)
select (Profile)Activator.CreateInstance(t);
var config = new MapperConfiguration(cfg =>
{
foreach (var profile in profiles)
{
cfg.AddProfile(profile);
}
});
For<MapperConfiguration>().Use(config);
For<IMapper>().Use(ctx => ctx.GetInstance<MapperConfiguration>().CreateMapper(ctx.GetInstance));
}
}
简单的注射器
?
这相当于:
container.RegisterInstance<MapperConfiguration>(config);
container.Register<IMapper>(() => config.CreateMapper(container.GetInstance));
Simple Injector 的 IPackage 接口似乎最接近 StructureMap 的 Registry 类型。这是我使用的包,从
using System;
using System.Linq;
using System.Reflection;
//
using AutoMapper;
//
using SimpleInjector;
using SimpleInjector.Packaging;
public class AutoMapperPackage : IPackage
{
public void RegisterServices(Container container)
{
var profiles = Assembly.GetExecutingAssembly()
.GetTypes()
.Where(x => typeof(AutoMapper.Profile).IsAssignableFrom(x));
var config = new MapperConfiguration(cfg =>
{
foreach (var profile in profiles)
{
cfg.AddProfile(Activator.CreateInstance(profile) as AutoMapper.Profile);
}
});
container.RegisterInstance<MapperConfiguration>(config);
container.Register<IMapper>(() => config.CreateMapper(container.GetInstance));
}
}
您需要添加 SimpleInjector.Packaging 包,然后在 bootstrap/configuration 代码中添加对 container.RegisterPackages();
的调用。
从本质上讲,与 StructureMap 唯一真正不同的是最后两行。
为了用不同的 MapperConfiguration 对象映射多个 IMapper,这似乎是一个反复出现的问题,我推荐以下方法,它甚至不需要重构映射器方法调用:
1) 在 IMapper 接口周围创建一个通用包装器。这个包装器可以是一个接口或 Class,但显然最终你必须实现你的包装器,所以我将在下面展示具体的 class。让这个包装器实现(或者继承,如果你选择创建一个接口) IMapper 接口,像这样:
public class ProfileMapper<TProfile> : IMapper where TProfile : Profile
{
private IMapper mapper;
private Profile profile;
public ProfileMapper(TProfile profile)
{
this.profile = profile;
this.mapper = new MapperConfiguration( cfg => cfg.AddProfile( this.profile ) )
.CreateMapper();
}
}
通用参数必须是 "Profile" 的子class,因为您将从该配置文件中获取映射器配置。
2) 在此 class 中,只需将调用重定向到您在构造函数中创建的私有 IMapper 实例,即可实现 IMapper 接口,如下所示:
public TDestination Map<TDestination>(object source)
{
return mapper.Map<TDestination>( source );
}
3) 现在您需要在 Simple Injector 中为您拥有的每个配置文件注册此 ProfileMapper class 的部分关闭实例。为此,您首先获取所有继承自 Profile 的 classes,然后创建这个部分关闭的实例并注册它。有几种方法可以获取所有配置文件 classes,但我选择了这个:
IEnumerable<Type> profileRegistrations =
from type in profileAssembly.GetExportedTypes()
where type.Namespace == "Namespace.Of.My.Profiles"
where type.BaseType.Equals( typeof( Profile ) )
select type;
foreach (Type profileType in profileRegistrations)
{
Container.RegisterSingleton( profileType, profileType );
Type mapperClosedType = typeof( ProfileMapper<> ).MakeGenericType( profileType );
Container.RegisterSingleton( typeof( ProfileMapper<> ), mapperClosedType );
}
此代码首先获取所有继承自配置文件的类型,位于所述命名空间中。然后对于每个配置文件,我用 SimpleInjector 注册它(不是真的必要,因为它们是具体类型,因此可以由容器即时创建),然后我创建一个部分关闭的 ProfileWrapper 实例 class 将当前 Profile 作为通用参数,最后我将关闭的实例注册为 Singleton。这样,您可以创建新的配置文件,而无需手动注册新的包装器。
就是这样。现在,您不再依赖和注入 IMapper,而是将您的 ProfileWrapper 注入您想要使用的配置文件,如下所示:
ProfileMapper<ApplicationProfile> appProfileMapper;
ProfileMapper<MvcProfile> mvcProfileMapper;
ProfileMapper<GuestProfile> guestProfile;
等等。每个 Wrapper 都是使用不同的配置文件使用单独的 MapperConfiguration 创建的。由于包装器实现了 IMapper,因此您的所有映射代码都保持不变。无需重构方法调用,只需重构依赖类型。
如果您创建一个 BaseProfile,只需将 ProfileMapper 中的通用参数更改为仅接受此 BaseProfile 的实例。