将依赖项注入 ASP.NET Core 中的 Automapper TypeConverter
Injecting dependencies to an Automapper TypeConverter in ASP.NET Core
要让 DI 框架将依赖项注入 Automapper 自定义 TypeConverter,通常使用 MapperConfiguration
对象的 ConstructServicesUsing
方法。因此,使用 ASP.NET Core DI,我希望能够像这样配置 AutoMapper:
public static IMapperConfiguration Configure(IServiceProvider provider)
{
var config = new MapperConfiguration(cfg => {
cfg.AddProfile<MyProfile>();
cfg.ConstructServicesUsing(type => provider.GetService(type));
});
config.AssertConfigurationIsValid();
return config;
}
MapperConfiguration
对象将在 startup.cs 中配置为可注入服务,因此:
public void ConfigureServices(IServiceCollection services)
{
//other service configuration omitted for simplicity
//Automapper config
var provider = services.BuildServiceProvider();
var config = AutoMapperConfig.Configure(provider);
services.AddInstance(config);
}
并且依赖项(在本例中为 Automapper 本身)将像这样注入到 TypeConverter 构造函数中。
public class MyConverter : ITypeConverter<ThisType, ThatType>
{
private IMapper _mapper;
public MyConverter(IMapperConfiguration mapperConfig)
{
var mc = mapperConfig as MapperConfiguration;
_mapper = mc.CreateMapper();
}
public ThatType Convert(ResolutionContext context)
{
//do something with _mapper here
}
}
我已经在几个 DI 框架中成功地使用了这个模式,但是我无法让它与 ASP.NET Core 一起工作。猜测,我认为可能需要在 ConfigureServices 方法完成后为 Automapper 提供由 .NET 构建的真实 IServiceProvider 实例。但是,即使我将那部分配置推迟到 Configure 方法(见下文),依赖项仍然没有注入到 TypeConverter。
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IServiceProvider provider)
{
var config = provider.GetService<IMapperConfiguration>();
config.ConstructServicesUsing(type => provider.GetService(type));
}
所以我的问题是:如何使用 ASP.NET Core 配置 Automapper,以便它向自定义 TypeConverter 注入依赖项?
您 can/should 使用工厂方法 inject/instantiate 服务。
services.AddSingleton<IMapperConfiguration>( (serviceProvider) => AutoMapperConfig.Configure(serviceProvider) );
这样您可以延迟对 Configure
的调用,直到 IMapperConfiguration
第一次被解析。由于它是单例,它将在您的应用程序容器的其余部分保持活动状态,并且对 RequestService
的进一步调用将 return 同一实例。
编辑:
尝试从您的 AutoMapperConfig.Configure
方法中删除 config.AssertConfigurationIsValid();
并在 Startup.cs
中添加以下代码
public void Configure(IServiceProvider app)
{
app.VerifyAutoMapperConfig();
}
AutoMapperConfigExtensions.cs
// So one doesn't have to add namespaces to become available
// inside Startup.cs; Recommended way all middleware register their
// AddXxx and UseXxx extension methods
namespace Microsoft.Extensions.DependencyInjection {
public static class AutoMapperConfigExtensions
{
public static void VerifyAutoMapperConfig(this IServiceProvider app)
{
var config = app.RequestService<IMapperConfiguration>();
config.AssertConfigurationIsValid();
}
}
}
我发现这个问题的解决办法在于ConstructServicesUsing
工厂方法的正确配置。正如@Tseng指出的那样,使用IServiceCollection.AddSingleton
方法可以让Automapper配置在Startup.cs的ConfigureServices
方法中,这是应该做的地方:
public void ConfigureServices(IServiceCollection services)
{
//other service configuration omitted for simplicity
//Automapper config
services.AddSingleton(provider => AutoMapperConfig.Configure(provider));
}
但至关重要的是,必须将 Automapper 配置为使用 .NET Core 的 ActivatorUtilities
class 来创建服务实例(感谢 this article 给我的想法):
public static IMapperConfiguration Configure(IServiceProvider provider)
{
var config = new MapperConfiguration(cfg => {
cfg.AddProfile<MyProfile>();
cfg.ConstructServicesUsing(type => ActivatorUtilities.CreateInstance(provider, type));
});
config.AssertConfigurationIsValid();
return config;
}
通过这种方法,Automapper 配置为将任何服务依赖项注入自定义 TypeConverters
和 ValueResolvers
。只需确保任何此类服务也已添加到 ConfigureServices
中的 IServiceCollection
实例。
要让 DI 框架将依赖项注入 Automapper 自定义 TypeConverter,通常使用 MapperConfiguration
对象的 ConstructServicesUsing
方法。因此,使用 ASP.NET Core DI,我希望能够像这样配置 AutoMapper:
public static IMapperConfiguration Configure(IServiceProvider provider)
{
var config = new MapperConfiguration(cfg => {
cfg.AddProfile<MyProfile>();
cfg.ConstructServicesUsing(type => provider.GetService(type));
});
config.AssertConfigurationIsValid();
return config;
}
MapperConfiguration
对象将在 startup.cs 中配置为可注入服务,因此:
public void ConfigureServices(IServiceCollection services)
{
//other service configuration omitted for simplicity
//Automapper config
var provider = services.BuildServiceProvider();
var config = AutoMapperConfig.Configure(provider);
services.AddInstance(config);
}
并且依赖项(在本例中为 Automapper 本身)将像这样注入到 TypeConverter 构造函数中。
public class MyConverter : ITypeConverter<ThisType, ThatType>
{
private IMapper _mapper;
public MyConverter(IMapperConfiguration mapperConfig)
{
var mc = mapperConfig as MapperConfiguration;
_mapper = mc.CreateMapper();
}
public ThatType Convert(ResolutionContext context)
{
//do something with _mapper here
}
}
我已经在几个 DI 框架中成功地使用了这个模式,但是我无法让它与 ASP.NET Core 一起工作。猜测,我认为可能需要在 ConfigureServices 方法完成后为 Automapper 提供由 .NET 构建的真实 IServiceProvider 实例。但是,即使我将那部分配置推迟到 Configure 方法(见下文),依赖项仍然没有注入到 TypeConverter。
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IServiceProvider provider)
{
var config = provider.GetService<IMapperConfiguration>();
config.ConstructServicesUsing(type => provider.GetService(type));
}
所以我的问题是:如何使用 ASP.NET Core 配置 Automapper,以便它向自定义 TypeConverter 注入依赖项?
您 can/should 使用工厂方法 inject/instantiate 服务。
services.AddSingleton<IMapperConfiguration>( (serviceProvider) => AutoMapperConfig.Configure(serviceProvider) );
这样您可以延迟对 Configure
的调用,直到 IMapperConfiguration
第一次被解析。由于它是单例,它将在您的应用程序容器的其余部分保持活动状态,并且对 RequestService
的进一步调用将 return 同一实例。
编辑:
尝试从您的 AutoMapperConfig.Configure
方法中删除 config.AssertConfigurationIsValid();
并在 Startup.cs
public void Configure(IServiceProvider app)
{
app.VerifyAutoMapperConfig();
}
AutoMapperConfigExtensions.cs
// So one doesn't have to add namespaces to become available
// inside Startup.cs; Recommended way all middleware register their
// AddXxx and UseXxx extension methods
namespace Microsoft.Extensions.DependencyInjection {
public static class AutoMapperConfigExtensions
{
public static void VerifyAutoMapperConfig(this IServiceProvider app)
{
var config = app.RequestService<IMapperConfiguration>();
config.AssertConfigurationIsValid();
}
}
}
我发现这个问题的解决办法在于ConstructServicesUsing
工厂方法的正确配置。正如@Tseng指出的那样,使用IServiceCollection.AddSingleton
方法可以让Automapper配置在Startup.cs的ConfigureServices
方法中,这是应该做的地方:
public void ConfigureServices(IServiceCollection services)
{
//other service configuration omitted for simplicity
//Automapper config
services.AddSingleton(provider => AutoMapperConfig.Configure(provider));
}
但至关重要的是,必须将 Automapper 配置为使用 .NET Core 的 ActivatorUtilities
class 来创建服务实例(感谢 this article 给我的想法):
public static IMapperConfiguration Configure(IServiceProvider provider)
{
var config = new MapperConfiguration(cfg => {
cfg.AddProfile<MyProfile>();
cfg.ConstructServicesUsing(type => ActivatorUtilities.CreateInstance(provider, type));
});
config.AssertConfigurationIsValid();
return config;
}
通过这种方法,Automapper 配置为将任何服务依赖项注入自定义 TypeConverters
和 ValueResolvers
。只需确保任何此类服务也已添加到 ConfigureServices
中的 IServiceCollection
实例。