automapper - Autofac 和 Automapper

标签 automapper autofac

我对 Autofac 与 Automapper 一起使用来映射对象的程度感到困惑。我在网上阅读了大量关于集成这两个包的 Material ,但几乎所有 Material 似乎都集中在如何从 Automapper 配置文件创建 IMapper 实例,使用类似这样的代码,它定义了一个 Autofac 模块(CSContainer.Instance 是一个Autofac 的 IContainer 的静态实例):

public class AutoMapperModule : Module
{
    private static object ServiceConstructor( Type type )
    {
        return CSContainer.Instance.Resolve( type );
    }

    protected override void Load( ContainerBuilder builder )
    {
        base.Load( builder );

        var assemblies = AppDomain.CurrentDomain.GetAssemblies();

        builder.RegisterAssemblyTypes( assemblies )
            .Where( t => typeof(Profile).IsAssignableFrom( t ) && !t.IsAbstract && t.IsPublic )
            .As<Profile>();

        builder.Register( c => new MapperConfiguration( cfg =>
            {
                cfg.ConstructServicesUsing( ServiceConstructor );

                foreach( var profile in c.Resolve<IEnumerable<Profile>>() )
                {
                    cfg.AddProfile( profile );
                }
            } ) )
            .AsSelf()
            .AutoActivate()
            .SingleInstance();

        builder.Register( c => c.Resolve<MapperConfiguration>().CreateMapper( c.Resolve ) )
            .As<IMapper>()
            .SingleInstance();
    }
}

(有关此方法的说明,请参阅 http://www.protomatter.co.uk/blog/development/2017/02/modular-automapper-registrations-with-autofac/)

我想做的是让 Automapper 调用 Autofac 来创建对象。目前,我能想到的唯一方法是执行以下操作:

创建 map () .ConstructUsing( src => CSContainer.Instance.Resolve() );

这可行,但感觉很笨拙。如果 Automapper 尝试发现如何在幕后自动使用 Autofac 解析实例,那就更简洁了。

我认为这样的东西可能会起作用(这是我上面引用的第一个 Autofac 模块的修改版本):

public class AutoMapperModule : Module
{
    protected override void Load( ContainerBuilder builder )
    {
        base.Load( builder );

        var assemblies = AppDomain.CurrentDomain.GetAssemblies();

        builder.RegisterAssemblyTypes( assemblies )
            .Where( t => typeof(Profile).IsAssignableFrom( t ) && !t.IsAbstract && t.IsPublic )
            .As<Profile>();

        builder.Register( c => new MapperConfiguration( cfg =>
            {
                cfg.ForAllMaps( ( map, opts ) =>
                    opts.ConstructUsing( ( x, y ) => CSContainer.Instance.Resolve(map.DestinationType) ) );

                foreach( var profile in c.Resolve<IEnumerable<Profile>>() )
                {
                    cfg.AddProfile( profile );
                }
            } ) )
            .AsSelf()
            .AutoActivate()
            .SingleInstance();

        builder.Register( c => c.Resolve<MapperConfiguration>().CreateMapper( c.Resolve ) )
            .As<IMapper>()
            .SingleInstance();
    }

但这导致 Autofac 抛出异常,提示我试图重用已经定义的构建器(抱歉,我手边没有确切的措辞)。

是否可以集成 Automapper 和 Autofac,以便 Automapper 通过 Autofac 解析新实例?如果是这样,最好的方法是什么?

其他信息

所以我按如下方式实现了建议的答案:

    protected override void Load( ContainerBuilder builder )
    {
        base.Load( builder );

        var assemblies = AppDomain.CurrentDomain.GetAssemblies();

        builder.RegisterAssemblyTypes( assemblies )
            .Where( t => typeof(Profile).IsAssignableFrom( t ) && !t.IsAbstract && t.IsPublic )
            .As<Profile>();

        builder.Register( c => new MapperConfiguration( cfg =>
            {
                cfg.ConstructServicesUsing( ServiceConstructor );

                foreach( var profile in c.Resolve<IEnumerable<Profile>>() )
                {
                    cfg.AddProfile( profile );
                }
            } ) )
            .AsSelf()
            .AutoActivate()
            .SingleInstance();

        builder.Register( c =>
            {
                // these are the changed lines
                var scope = c.Resolve<ILifetimeScope>();
                return new Mapper(c.Resolve<MapperConfiguration>(), scope.Resolve );
            } )
            .As<IMapper>()
            .SingleInstance();
    }

但这会导致 Automapper 异常,提示我试图通过调用 Map() 创建的对象必须有零个参数,或者只有可选参数。然而,所有对象的构造函数参数也都注册到 Autofac,并且在我的代码中的其他地方自行创建对象的实例没有问题。只是当 Automapper 尝试创建一个实例时,事情就变得困惑了。

最佳答案

来自the docsthe source看起来您可以将函数传递给 Mapper构造函数将通过该函数运行所有服务位置。

public Mapper(IConfigurationProvider configurationProvider, Func<Type, object> serviceCtor)

This blog article有更详细的示例并解释了如何将 ASP.NET Core DI 与 AutoMapper 连接起来。不要执着于它是 ASP.NET Core - 您将为 Autofac 遵循相同的原则。

builder.Register(
  ctx =>
  {
    var scope = ctx.Resolve<ILifetimeScope>();
    return new Mapper(
      ctx.Resolve<IConfigurationProvider>(),
      scope.Resolve);
  })
  .As<IMapper>()
  .InstancePerLifetimeScope();

您的工作只是弄清楚如何将您的配置注册为 IConfigurationProvider .

关于automapper - Autofac 和 Automapper,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50264267/

相关文章:

c# - AutoMapper 根据其他模型属性值映射所有属性

c# - 要列出的数据表 - AutoMapperException 或值未映射

c# - DTO 形状 : flat, 复杂/嵌套,或两者的混合

wpf - 未找到方法 : 'Void Caliburn.Micro.Bootstrapper` 1. .ctor(Boolean)'

c# - AutoMapper:如何从 String 解析 Int 并可能根据数据类型创建规则?

c# - 更新到 Automapper v5 时出现 .NullSubstitute 错误

c# - 无法使用 JustMock 模拟简单对象数组

c# - Bot Framework Autofac DI - 使用 context.Call() 时传递依赖项

inversion-of-control - 使用 Autofac 有什么优点和缺点

c# - 无法使用 Autofac 解析 NameValueCollection