使用 Autofac 实现 N 层架构时获取空参数
Getting null argument when implementing N-tiers architecture with Autofac
我创建了这个包含以下库的简单 WebAPI 项目 class
- 协调(服务层)
- 域(业务层)
- 数据(数据层)
- 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;
}
}
- 出现了一些问题。首先它不知道如何找到域,因为理论上 WebAPI 不与域层对话。
- 我确实将其添加为参考,但现在出现空参数错误。服务类型不能为空。
我从服务实现中没有想到什么
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;
}
}
这是我不断收到的错误
很抱歉我的 os 是法语,但这只是意味着该值为空。
全栈错误
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);
}
}
好像注册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()
可能你会want/need区分带接口和不带接口的类型,你可以尝试下一种方法:
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();
P.S.
另外,我建议将所有 Assembly.Load(nameof(SOME_NAME))
更改为 typeof(TYPE_NAME).Assembly
,我认为它更具可读性和明显性。
我创建了这个包含以下库的简单 WebAPI 项目 class
- 协调(服务层)
- 域(业务层)
- 数据(数据层)
- 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;
}
}
- 出现了一些问题。首先它不知道如何找到域,因为理论上 WebAPI 不与域层对话。
- 我确实将其添加为参考,但现在出现空参数错误。服务类型不能为空。
我从服务实现中没有想到什么
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;
}
}
这是我不断收到的错误
很抱歉我的 os 是法语,但这只是意味着该值为空。 全栈错误
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);
}
}
好像注册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()
可能你会want/need区分带接口和不带接口的类型,你可以尝试下一种方法:
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();
P.S.
另外,我建议将所有 Assembly.Load(nameof(SOME_NAME))
更改为 typeof(TYPE_NAME).Assembly
,我认为它更具可读性和明显性。