将依赖项注入 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 配置为将任何服务依赖项注入自定义 TypeConvertersValueResolvers。只需确保任何此类服务也已添加到 ConfigureServices 中的 IServiceCollection 实例。