首页 文章

向ASP.NET Core中的Automapper TypeConverter注入依赖项

提问于
浏览
2

要获得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,以便将依赖项注入自定义TypeConverters?

2 回答

  • 4

    我发现这个问题的解决方案在于 ConstructServicesUsing 工厂方法的正确配置 . 正如@Tseng所指出的那样,使用 IServiceCollection.AddSingleton 方法可以在Startup.cs的 ConfigureServices 方法中配置Automapper,这是它应该完成的地方:

    public void ConfigureServices(IServiceCollection services)
    {
        //other service configuration omitted for simplicity
    
        //Automapper config
        services.AddSingleton(provider => AutoMapperConfig.Configure(provider));
    }
    

    但至关重要的是,Automapper必须配置为使用.NET Core的 ActivatorUtilities 类来创建服务实例(归功于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 实例中 .

  • 1

    您可以/应该使用工厂方法来注入/实例化服务 .

    services.AddSingleton<IMapperConfiguration>( (serviceProvider) => AutoMapperConfig.Configure(serviceProvider) );
    

    这样就可以将调用延迟到 Configure ,直到第一次解析 IMapperConfiguration 为止 . 由于它是单例,它将为您的应用程序容器的其余部分保持活动状态,并且对 RequestService 的进一步调用将返回相同的实例 .

    Edit:

    尝试从 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();
            }
        }
    }
    

相关问题