【问题标题】:Getting null argument when implementing N-tiers architecture with Autofac使用 Autofac 实现 N 层架构时获取空参数
【发布时间】:2020-05-28 15:46:13
【问题描述】:

我创建了这个简单的 WebAPI 项目,其中包含以下库类

  • 协调(ServiceLayer)
  • 域(业务层)
  • 数据(DataLayer)
  • Dtos(Webapi 的 Dtos)

基本上是 WebAPI 项目调用(参考)Dtos 和协调。协调调用域和域调用数据。

这就是我的结构的样子。

我的问题是使用 Autofac 实现依赖注入。我可以调用协调层,当我尝试调用域层时,这会让人感到困惑。

这就是我定义寄存器类型的方式

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;
        }
    }

这是我不断收到的错误

对不起,我的操作系统是法语,但这只是意味着值为空。 全栈错误

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);
        }
    }

【问题讨论】:

  • 请将完整的异常详细信息(包括异常的堆栈跟踪和所有内部异常)添加到您的问题中。 (没有截图,只有文字)就目前而言,任何人都无法回答您的问题,因为失败的原因不太可能在您提供的代码中。必须创建更多的上下文。您的问题也感觉像是“如何调试我的代码”之类的问题,不适合 Stack Overflow。
  • 尝试在一个小的新项目中重现该问题也很好。从一个空项目开始,然后逐渐添加代码,直到你偶然发现问题。然后按原路返回,直到找到异常原因。
  • 我知道如果我删除 builder.RegisterAssemblyTypes(Assembly.Load(nameof(Domain))) 我可以让它工作,但我现在无法实现我的业务层。
  • 我认为问题是由于加载了 FirstOrDefault 调用返回 null 的类型。
  • 根据您的评论,我确实将第二个 builder.reg... 行更改为此 builder.RegisterType().As();这行得通。但是我不想从我的域层单独定义我的所有接口我如何搜索所有这些接口

标签: c# asp.net-web-api dependency-injection autofac


【解决方案1】:

注册Domain好像有问题,因为StudentEntity没有对应的接口,.As(j =&gt; j.GetInterfaces().FirstOrDefault(i =&gt; i.Name == "I" + j.Name))会找不到对应的接口。

如果您不想手动添加带有接口的所有类型,请尝试以下操作:

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

您可能想要/需要区分有接口和没有接口的类型,您可以尝试下一种方法:

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();

附言

另外我会建议将所有Assembly.Load(nameof(SOME_NAME)) 更改为typeof(TYPE_NAME).Assembly,我认为它更具可读性和明显性。

【讨论】:

  • 当我将 load(nameof(type_name)) 更改为 typeof(type_name).assembly 时出现以下错误:Domain is a namespace but is used as a type.
  • 抱歉,请在相应的程序集中使用typeof(StudentDomain) 或任何其他类型。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-01
  • 1970-01-01
  • 2011-07-06
  • 2012-03-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多