本文是介绍netcore2.x版本的autofac的使用,以下是netcore3.0的
NetCore3.0面向接口编程中,Autofac(依赖注入)的基本使用
项目基本介绍
备注,项目源代码在上传GitHub后会展示链接
项目用的面向接口编程
(PS:面向接口编程的核心含义就是,层与层之间只通过接口关联)
EptDemo是API主程序:依赖于IRepo和IServ
EptDemo.IRepo是仓储接口层,负责提供Repo层的接口
EptDemo.Repo是仓储层,负责与数据库进行数据串接,依赖Repo
EptDemo.IServ是服务接口层,一般只提供给主程序,依赖于IRepo
EptDemo.Serv是服务层,作用是完成与Repo层的数据串接,依赖于IRepo和IServe层
autofac实现依赖注入
安装扩展包
管理nugut安装下载Autofac及其扩展包
Autofac.Extensions.DependencyInjection
Autofac.Extras.DynamicProxy
注册服务
在startup.cs中ConfigureServices中注册
先写最简单的代码
基本
//获取项目路径
var basePath = AppContext.BaseDirectory;
//初始化AutoFac容器
var builder = new ContainerBuilder();
#region 可升级代码
//普通注入,与netcore本身提供netcore一致
builder.RegisterType<DemoServices>().As<IDemoServices>();
builder.RegisterType<DemoRepository>().As<IDemoRepository>();
#endregion
//将services填充Autofac容器生成器
builder.Populate(services);
//使用已创建的组件登记创建新容器
var ApplicationContainer = builder.Build();
//第三方IOC接管 core内置DI容器
return new AutofacServiceProvider(ApplicationContainer);
效果和 services.AddScoped<IDemoServices, DemoServices>();一致
注意:以上代码需要添加repository和services的引用
进阶
实际上,我们的services和repository后续会越来越多,这样做会很麻烦,那能不能一次性全部匹配呢。答案是可以的
进阶一:反射加载
通过反射加载程序集,然后进行依赖注入
将“可升级代码”更新成以下代码
#region 加载引用注入
//通过反射加载services程序集
var assemblyServices = Assembly.Load("EptDemo2.Services");
//指定已扫描程序集中的类型注册为提供所有其实现的接口
builder.RegisterAssemblyTypes(assemblyServices).AsImplementedInterfaces();
//通过反射加载repository
var assemblyRepository = Assembly.Load("EpteDemo2.Repository");
builder.RegisterAssemblyTypes(assemblyRepository).AsImplementedInterfaces();
#endregion
作用:就是通过命名空间,反射加载程序集,然后达成依赖注入的效果
注意:此方法也需要services层和repository层的引用,这样才能访问到对应的命名空间
进阶二:松耦合
批量注入的效果是达到了,但是有一个效果没有达到,就是松耦合。
我们面向接口编程其实最重要的就是为了达成这种效果。而上面的代码,依然还是需要添加repository和serivices的引用,那其实耦合度还是比较高。
而这个时候,如果想要达成效果,一般会采用加载dll的方法。
步骤一:更换dll生成路径
- 将repository和services的dll生成路径放到主程序上(EptDemo2):右键repository -属性-编译-输出路径:将路径改为 …\EptDemo2\bin\Debug\
- services同上
- 重新编译这两个项目(右键项目-编译)
注意:输出路径是两个 逗号
步骤二:将“可升级代码”更新成如下
var basePath = AppContext.BaseDirectory;
var servicesDllFile = Path.Combine(basePath, "EptDemo2.Services.dll");
var assemblyServices = Assembly.LoadFile(servicesDllFile);
builder.RegisterAssemblyTypes(assemblyServices).AsImplementedInterfaces();
var repositoryDllFile = Path.Combine(basePath, "EptDemo2.Repository.dll");
var assemblyRepository = Assembly.LoadFile(repositoryDllFile);
builder.RegisterAssemblyTypes(assemblyRepository).AsImplementedInterfaces();
之后将整个解决方案,重新编译即可
此种方法,在每次更新repository和services的代码时,都需要重新编译才能生效。
切记切记
常见异常:
None of the constructors found with ‘Autofac.Core.Activators.Reflection.DefaultConstructorFinder’ on type ‘EptDemo2.Services.DemoServices’ can be invoked with the available services and parameters:
Cannot resolve parameter ‘EptDemo2.IRepository.IDemoRepository demoRepository’ of constructor ‘Void .ctor(EptDemo2.IRepository.IDemoRepository)’.
这种问题的根因是在于autofac没有找到匹配的匹配的实现。
可能原因
- 在autofac中,没有找到对应的实现代码,例如IServices没有找到Servcies的实例。
那问题就在于auto部分代码写错。最有可能的就是dll文件路径加了I,写成了IRepository。-_-别问我咋知道 - .在serviecs中,没有写构造函数,导致没有把repository写入到services的构造方法,如下图