首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Autofac和Automapper

Autofac和Automapper
EN

Stack Overflow用户
提问于 2018-05-10 01:38:20
回答 2查看 11.9K关注 0票数 4

我不知道Autofac在多大程度上可以与Automapper一起使用来映射对象。我在网上读过很多关于集成这两个包的材料,但几乎所有的内容似乎都集中在如何使用类似于这样的代码从Automapper创建IMapper实例,该代码定义了一个Autofac模块(CSContainer.Instance是Autofac的IContainer的一个静态实例):

代码语言:javascript
复制
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来创建对象。现在我能看到的唯一方法就是做这样的事情:

CreateMap() .ConstructUsing( src => CSContainer.Instance.Resolve() );

这很管用,但感觉很疯狂。如果Automapper试图发现如何自动地使用Autofac解析实例,那么它会更整洁。

我想像这样的东西可能会起作用(这是我前面提到的第一个Autofac模块的修改版本):

代码语言:javascript
复制
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解析新实例?如果是的话,最好的方法是什么?

附加信息

因此,我将建议的答案执行如下:

代码语言:javascript
复制
    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试图创建一个实例时,事情就变得一团糟了。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-05-10 15:21:12

医生们来源看来,您可以将一个函数传递给将通过该函数运行所有服务位置的Mapper构造函数。

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

这篇博客文章有更详细的示例,并解释了如何将ASP.NET Core与AutoMapper连接起来。不要因为它是ASP.NET核心而挂断--对于Autofac,您将遵循同样的原则。

代码语言:javascript
复制
builder.Register(
  ctx =>
  {
    var scope = ctx.Resolve<ILifetimeScope>();
    return new Mapper(
      ctx.Resolve<IConfigurationProvider>(),
      scope.Resolve);
  })
  .As<IMapper>()
  .InstancePerLifetimeScope();

您的工作只是研究如何将您的配置注册为IConfigurationProvider

票数 7
EN

Stack Overflow用户

发布于 2018-05-11 18:14:10

我发这篇文章是作为一个答案,但不是>>the<<的答案,因为我想给@TravisIllig一个荣誉,因为没有他的输入,我就无法解决我的问题。

但是,对于Automapper使用Autofac来创建实例来说,还有一个重要但并不明显的步骤需要实现:当您定义一个映射时,您必须显式地声明您希望使用服务定位器构造对象。示例:

代码语言:javascript
复制
CreateMap<CommunityUserModel, CommunityUserModel>()
    .ConstructUsingServiceLocator()
    .AfterMap( ( src, dest ) => dest.ClearChanged() );

如果不使用第二行,Automapper将使用它的默认方法来查找无参数或唯一可选的参数构造函数。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50264267

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档