Получение нулевого аргумента при реализации N-уровневой архитектуры с Autofac - PullRequest
0 голосов
/ 28 мая 2020

Я создал этот простой проект WebAPI, содержащий следующий класс библиотеки

  • Координация (ServiceLayer)
  • Домен (BusinessLayer)
  • Data (DataLayer)
  • Dtos (Dtos для webapi)

В основном проект WebAPI вызывает (справку) Dtos и координацию. Координация вызовов домена и данных вызовов домена.

Вот как выглядит моя структура.

enter image description here

Мои проблемы связаны с внедрением зависимостей с использованием Автодиван c. Я могу вызвать уровень координации, когда я пытаюсь вызвать уровень домена, здесь он запутывается.

Вот как я определил свой тип реестра

public class AutofacWebapiConfig
    {

        public static IContainer Container;

        public static void Initialize(HttpConfiguration config)
        {
            Initialize(config, RegisterServices(new ContainerBuilder()));
        }

        public static void Initialize(HttpConfiguration config, IContainer container)
        {
            config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
        }

        private static IContainer RegisterServices(ContainerBuilder builder)
        {
            //Register your Web API controllers.  
            builder.RegisterApiControllers(Assembly.GetExecutingAssembly());

            builder.RegisterAssemblyTypes(Assembly.Load(nameof(Coordination)))
              .Where(t => t.Namespace.Contains("Services"))
              .As(t => t.GetInterfaces().FirstOrDefault(i => i.Name == "I" + t.Name));

            builder.RegisterAssemblyTypes(Assembly.Load(nameof(Domain)))
              .Where(j => j.Namespace.Contains("Domain"))
              .As(j => j.GetInterfaces().FirstOrDefault(i => i.Name == "I" + j.Name));

            //Set the dependency resolver to be Autofac.  
            Container = builder.Build();

            return Container;
        }

    }
  1. Несколько проблем происходит. Сначала он не знает, как найти домен, потому что теоретически WebAPI не взаимодействует с уровнем домена.
  2. Я добавил его как ссылку, но теперь я получаю ошибку нулевого аргумента. ServiceType не может быть нулевым.

Ничего такого, что выскакивает из меня из реализации службы

 public class StudentService : IStudentService
    {
        private readonly IStudentDomain studentDomain;
        public StudentService(IStudentDomain _studentDomain)
        {
            this.studentDomain = _studentDomain;
        }

        public async Task<StudentDto> GetStudentByID(string id)
        {
            var test = this.studentDomain.getStudentByID(id);
        }
}

А вот моя реализация домена

    public class StudentDomain : IStudentDomain
    {

        public StudentDomain()
        {

        }

        /// <summary>
        /// Return student
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        StudentEntity IStudentDomain.getStudentByID(string id)
        {
            StudentEntity student = new StudentEntity("dd", "aa", "ddd");
            return student;
        }
    }

Это ошибка, которую я получаю enter image description here

Мне очень жаль, что моя ОС французская, но это просто означает, что значение равно нулю. Ошибка полного стека

System.ArgumentNullException
  HResult=0x80004003
  Message=La valeur ne peut pas être null.
Nom du paramètre : serviceType
  Source=Autofac
  StackTrace:
   at Autofac.Core.TypedService..ctor(Type serviceType)
   at Autofac.RegistrationExtensions.<>c__DisplayClass14_0`3.<As>b__0(Type t)
   at Autofac.RegistrationExtensions.<>c__DisplayClass13_0`3.<As>b__0(Type t)
   at Autofac.Features.Scanning.ScanningRegistrationExtensions.<>c__DisplayClass8_0`3.<As>b__0(Type t, IRegistrationBuilder`3 rb)
   at Autofac.Features.Scanning.ScanningRegistrationExtensions.ScanTypes(IEnumerable`1 types, IComponentRegistryBuilder cr, IRegistrationBuilder`3 rb)
   at Autofac.Features.Scanning.ScanningRegistrationExtensions.ScanAssemblies(IEnumerable`1 assemblies, IComponentRegistryBuilder cr, IRegistrationBuilder`3 rb)
   at Autofac.Features.Scanning.ScanningRegistrationExtensions.<>c__DisplayClass0_0.<RegisterAssemblyTypes>b__0(IComponentRegistryBuilder cr)
   at Autofac.ContainerBuilder.Build(IComponentRegistryBuilder componentRegistry, Boolean excludeDefaultModules)
   at Autofac.ContainerBuilder.Build(ContainerBuildOptions options)
   at CB.WebAPI.App_Start.AutofacWebapiConfig.RegisterServices(ContainerBuilder builder) in C:\source\repos\CB.WebAPI\CB.WebAPI\App_Start\AutofacWebapiConfig.cs:line 43
   at CB.WebAPI.App_Start.AutofacWebapiConfig.Initialize(HttpConfiguration config) in C:\source\repos\CB.WebAPI\CB.WebAPI\App_Start\AutofacWebapiConfig.cs:line 21
   at CB.WebAPI.App_Start.Bootstrapper.Run() in C:\source\repos\CB.WebAPI\CB.WebAPI\App_Start\Bootstrapper.cs:line 14
   at CB.WebAPI.WebApiApplication.Application_Start() in C:\source\repos\CB.WebAPI\CB.WebAPI\Global.asax.cs:line 18

Здесь я добавляю файл global.asax.cs. Строка 18 - это мой bootstrapper.run ();

    public class WebApiApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            Bootstrapper.Run();
            GlobalConfiguration.Configure(WebApiConfig.Register);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
        }
    }

1 Ответ

2 голосов
/ 28 мая 2020

Похоже, что есть проблема с регистрацией Domain, потому что StudentEntity не имеет соответствующего интерфейса, и .As(j => j.GetInterfaces().FirstOrDefault(i => i.Name == "I" + j.Name)) не сможет найти для него.

Если вы не хотите вручную добавьте все типы с интерфейсами, попробуйте следующее:

builder.RegisterAssemblyTypes(typeof(StudentDomain).Assembly)
          .Where(j => j.Namespace.Contains("Domain"))
          .AsImplementedInterfaces()

Возможно, вам понадобится / нужно различать guish между типами с интерфейсами и без них, вы можете попробовать следующий подход:

builder.RegisterAssemblyTypes(typeof(StudentDomain).Assembly)
          .Where(j => j.Namespace.Contains("Domain") && j.GetInterfaces().Any())
          .AsImplementedInterfaces()

builder.RegisterAssemblyTypes(typeof(StudentDomain).Assembly)
          .Where(j => j.Namespace.Contains("Domain") && !j.GetInterfaces().Any())
          .AsSelf();

PS

Так же рекомендовал бы поменять все Assembly.Load(nameof(SOME_NAME)) на typeof(TYPE_NAME).Assembly, думаю это более читабельно и наглядно.

...