【问题标题】:Automapper & Autofac typeconverter - does not have a default constructorAutomapper 和 Autofac 类型转换器 - 没有默认构造函数
【发布时间】:2020-07-22 18:25:15
【问题描述】:

我在将 aufotac 注入我的 autopmapper 类型转换器时遇到问题。我尝试了一些不同的方法,但我目前无法使用下面的代码。我找到解决方案最接近的是下面的代码(从http://thoai-nguyen.blogspot.se/2011/10/autofac-automapper-custom-converter-di.html借来的小代码)。他的样本似乎可以 1:1 工作,但无法找到我缺少的东西。像往常一样提取了相关的部分,如果不够,请告诉我。

我的 autofac 引导程序:

public class AutoFacInitializer
    {
        public static void Initialize()
        {
            //Mvc
            var MvcContainer = BuildMvcContainer();
            DependencyResolver.SetResolver(new AutofacDependencyResolver(MvcContainer));

            //Web API
            var ApiContainer = BuildApiContainer();
            var ApiResolver = new AutofacWebApiDependencyResolver(ApiContainer);
            GlobalConfiguration.Configuration.DependencyResolver = ApiResolver;
        }

        private static IContainer BuildApiContainer()
        {
            var builder = new ContainerBuilder();
            var assembly = Assembly.GetExecutingAssembly();
            builder.RegisterApiControllers(assembly);
            return BuildSharedDependencies(builder, assembly);
        }

        private static IContainer BuildMvcContainer()
        {
            var builder = new ContainerBuilder();
            var assembly = typeof (MvcApplication).Assembly;
            builder.RegisterControllers(assembly);
            builder.RegisterFilterProvider();
            return BuildSharedDependencies(builder, assembly);
        }

        private static IContainer BuildSharedDependencies(ContainerBuilder builder, Assembly assembly)
        {
            //----Build and return container----
            IContainer container = null;

            //Automapper
            builder.RegisterAssemblyTypes(assembly).AsClosedTypesOf(typeof(ITypeConverter<,>)).AsSelf();
            AutoMapperInitializer.Initialize(container);
            builder.RegisterAssemblyTypes(assembly).Where(t => typeof(IStartable).IsAssignableFrom(t)).As<IStartable>().SingleInstance();

            //Modules
            builder.RegisterModule(new AutofacWebTypesModule());
            builder.RegisterModule(new NLogLoggerAutofacModule());

            //Automapper dependencies
            builder.Register(x => Mapper.Engine).As<IMappingEngine>().SingleInstance();

            //Services, repos etc
            builder.RegisterGeneric(typeof(SqlRepository<>)).As(typeof(IRepository<>)).InstancePerDependency();
            
            container = builder.Build();
            return container;
        }
    }

我的 Automap 引导程序/初始化程序:

namespace Supportweb.Web.App_Start
{
    public class AutoMapperInitializer
    {
        public static void Initialize(IContainer container)
        {
            Mapper.Initialize(map =>
            {
                map.CreateMap<long?, EntityToConvertTo>().ConvertUsing<LongToEntity<NavigationFolder>>();

                map.ConstructServicesUsing(t => container.Resolve(t)); 
            });
            Mapper.AssertConfigurationIsValid();
        }
    }
}

我试图开始工作的类型转换器:

public class LongToEntity<T> : ITypeConverter<long?, T>
    {
        private readonly IRepository<T> _repo;

        public LongToEntity(IRepository<T> repo)
        {
            _repo = repo;
        }

        public T Convert(ResolutionContext context) 
        {
            long id = 0;
            if (context.SourceValue != null)
                id = (long)context.SourceValue;
            return _repo.Get(id);
        }
    }

除了转换器,所有映射都可以正常工作。该错误似乎表明我缺少 ioc 引用,但我已经尝试过,但提到的 ITypeConverter 和 LongToEntity 以及似乎没有帮助的变体。

【问题讨论】:

    标签: c# automapper autofac


    【解决方案1】:

    您当前的代码存在三个问题:

    1. 您需要致电ConstructServicesUsing按照链接文章中的说明注册任何映射:

      棘手的是我们需要在注册映射器类之前调用​​该方法。

      所以正确的Mapper.Initialize 如下:

      Mapper.Initialize(map =>
              {
                  map.ConstructServicesUsing(t => container.Resolve(t));  
      
                  map.CreateMap<long?, EntityToConvertTo>()
                      .ConvertUsing<LongToEntity<NavigationFolder>>();
              });
      
    2. 因为您的LongToEntity&lt;T&gt; 是一个开放的泛型,您不能使用AsClosedTypesOf,但您还需要在此处使用RegisterGeneric 进行注册:

      因此,将您的ITypeConverter&lt;,&gt; 注册从:

       builder.RegisterAssemblyTypes(assembly)
              .AsClosedTypesOf(typeof(ITypeConverter<,>)).AsSelf();
      

      要使用RegisterGeneric 方法:

       builder.RegisterGeneric(typeof(LongToEntity<>)).AsSelf();
      
    3. 由于您已将 Automapper 初始化移动到单独的方法 AutoMapperInitializer.Initialize 中,因此您无法使用文章中的 clojure 技巧,因此您需要在创建容器后调用它:

       container = builder.Build();
       AutoMapperInitializer.Initialize(container);
       return container;
      

    【讨论】:

    • 感谢输入。我之前已经移动了初始化程序和构造服务,但没有注意到任何差异。虽然完全忽略了 registergeneric 部分。根据您的建议进行了调整,现在在运行时出现另一个错误,“从请求实例的范围内看不到标签匹配 'AutofacWebRequest' 的范围。”
    • 那么你有一个完全不相关的问题,现在 Autofac 分辨率开始工作了。您应该在不同的问题中提出这个问题,但首先查看这个问题:stackoverflow.com/questions/12802073/… 这似乎与您的问题相似。
    • 如果没有看到您的完整注册,很难说出导致问题的原因。可能在您的LongToEntity 中,您正在引用(可能在IRepository 实现中)一些在InstancePerLifetimeScope 注册的类型...
    • 找到了。我将我的 DbContext 注入为“InstancePerHttpRequest”。当更改为每个依赖项时,它可以工作=这是我错过的通用注册让我很头疼,所以感谢您引导我走上正确的道路;)认为我在早些时候以默认方式注入时遇到了问题,但现在似乎正在工作。无论如何,主要问题现在似乎已经解决了!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-01
    • 2023-03-20
    • 2016-07-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多