序言
.NET Core WebApi开发 - 掘金 (juejin.cn) 上篇文章介绍了.NET Core自带的IOC容器,可以实现多重方式的DI依赖注入,但是,随着业务的增多,Repository和Service层文件的增加,我们不可能去每个文件都单独的添加到容器中,那我们怎么去实现批量注入呢,所以就有了第三方的IOC容器Autofac,Autofac的功能非常强大,但是我们不一定全部都用得到,此篇文章只说明批量注入的使用,感兴趣的可以去官网了解下。Autofac
Autofac方法介绍
此处有借鉴:AutoFac中常用方法说明 - bxzjzg - 博客园 (cnblogs.com)
这里稍微介绍下Autofac的api
AsImplementedInterfaces
是以接口方式进行注入,注入这些类的所有的公共接口作为服务
InstancePerRequest
每次请求共享同一个实例,使用ef时,使不同的操作使用同一个数据上下文
PreserveExistingDefaults
如果不止一个组件暴露了相同的服务, Autofac将使用最后注册的组件作为服务的提供方,那么使用PreserveExistingDefaults防止后面注册的覆盖前面注册的
builder.Register<A>().As<IA>();
builder.Register<AA>().As<IA>(); //这样AA就会覆盖A
builder.Register<AA>().As<IA>().PreserveExistingDefaults(); //这样A是IA的默认值,不会被AA覆盖
InstancePerDependency
为每个依赖或者调用(Resolve())都创建一个新的对象,唯一的实例
SingleInstance
为每次请求都使用同一个对象,单例模式.告诉容器,是个单例,但这个单例不用自己实现。
RegisterGeneric
对泛型类进行注册
builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepository<>));
RegisterInstance
注册一个实例,比如: 对已经存在的对象的实例进行注册,这样可以使实例转化为由容器托管的实例
RegisterControllers
注册Controllers
builder.RegisterControllers(Assembly.GetExecutingAssembly()); //注册当前程序集中的所有Controllers
RegisterFilterProvider
注册Filter过滤器
builder.RegisterFilterProvider()
RegisterAssemblyTypes
注册类
builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly());//注册了当前程序集内的所有的类
InstancePerMatchingLifetimeScope
在一个做标识的生命周期域中,每一个依赖或调用创建一个单一的共享的实例。打了标识了的生命周期域中的子标识域中可以共享父级域中的实例
builder.RegisterType<A>().AsImplementedInterfaces().InstancePerMatchingLifetimeScope();
InstancePerHttpRequest
在一次Http请求上下文中,共享一个组件实例。仅适用于asp.net mvc开发
InstancePerLifetimeScope
在一个生命周期中,每一次的依赖组件或调用(Resolve())创建一个单一的共享的实例,且每一个不同的生命周期域,实例是不同的
UsingConstructor
自动装配,手动使用特定的构造函数
builder.RegisterType<A>().UsingConstructor(typeof(IA),typeof(IAA)); //这样指定调用的是A(IA,IAA)的构造函数,如果该构造函数不存在则报错
PropertiesAutowired
配置组件,以便其类型在容器中注册的任何属性都将连接到相应服务的实例。
EnableInterfaceInterceptors 在目标类型上启用接口拦截。侦听器将通过类或接口上的 Intercept 属性确定,或者使用 InterceptedBy()调用添加。
InterceptedBy
允许将侦听器服务列表分配给注册。
[AsClosedTypesOf(open)]AsClosedTypesOf(typeof(IA<>)):
如果是多继承的话,注册的程序集所对应的服务(接口)是离这个类最近的开放的泛型实例(接口)
builder.RegisterAssemblyTypes(A).AsClosedTypesOf(typeof(IRepository<>));
如何实现批量注入
一步一步来,我们先创建Repository和Service的类库
代码也很简单的写了个测试的方法
public interface ITestRepository
{
public string GetTestData();
}
public class TestRepository : ITestRepository
{
public string GetTestData()
{
return "Class TestRepository Method GetTestData:测试数据";
}
}
public interface ITestService
{
public string Test(string str);
}
public class TestService : ITestService
{
ITestRepository testRepository;
public TestService(ITestRepository _testRepository)
{
testRepository= _testRepository;
}
public string Test(string str)
{
string data=testRepository.GetTestData();
return $"Class TestService Method Test Paramter:{str} TestData:{data}";
}
}
好的,我们看到这里TestServer的构造函数中我们也注入了Repository,那这种架构方式该如何注入到容器中呢? 我们先看下用.NET Core自带的IOC容器如何操作的。
services.AddScoped<ITestRepository, TestRepository>();
services.AddScoped<ITestService, TestService>();
现在看着只有一个Service和一个Repository文件的情况下我们都需要单独的注入,那当我们业务复杂起来后肯定也会越来越多,那肯定是不便于开发的。而Autofac则能够实现批量注入,那我们来看下应该如何实现呢?
首先我们需要引入Autofac对应的包
<PackageReference Include="Autofac" Version="6.3.0" />
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="7.2.0" />
<PackageReference Include="Autofac.Extras.DynamicProxy" Version="6.0.1" />
创建一个注册的类,并且继承Autofac.Module,重写Load方法,下面代码能够看到是可以通过dll(动态链接库)文件来实现注入的,那就是说,项目可以不引用这两个项目,只用把生成的dll放到指定的位置去读取就行了,能够实现项目之间的解耦。
/// <summary>
/// 注入Service和Repository
/// </summary>
public class AutofacRegister : Autofac.Module
{
protected override void Load(ContainerBuilder builder)
{
var basePath = AppContext.BaseDirectory;
var servicesDllFile = Path.Combine(basePath, "Service.dll");
var repositoryDllFile = Path.Combine(basePath, "Repository.dll");
// 获取 Service.dll 程序集服务,并注册
var assemblysServices = Assembly.LoadFrom(servicesDllFile);
builder.RegisterAssemblyTypes(assemblysServices)
.AsImplementedInterfaces()
.InstancePerDependency()
.PropertiesAutowired();
// 获取 Repository.dll 程序集服务,并注册
var assemblysRepository = Assembly.LoadFrom(repositoryDllFile);
builder.RegisterAssemblyTypes(assemblysRepository)
.AsImplementedInterfaces()
.InstancePerDependency()
.PropertiesAutowired();
}
}
下一步就是在Program里面启用Autofac工厂
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseServiceProviderFactory(new AutofacServiceProviderFactory())//启用Autofac工厂
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
}).UseNLog();//启用NLog
在Startup文件中调用我们刚才写的AutofacRegister,直接新增一个ConfigureContainer方法
public void ConfigureContainer(ContainerBuilder builder)
{
builder.RegisterModule(new AutofacRegister());
}
好了,我们在控制器中调用Service方法看看效果。
[Route("api/[controller]")]
[ApiController]
public class TestController : ControllerBase
{
private readonly ITestService _testServer;
public TestController(ITestService testServer)
{
_testServer = testServer;
}
[HttpGet("TestService")]
public string TestService(string str)
{
return _testServer.Test(str);
}
}
完美运行,看到返回结果也是正常的。
总结
Autofac功能比较强大,还有很多功能没有用到,在日常开发中,如果没有多层的架构或者没有面向接口开发也用不到,但是多层架构也有诸多的好处。具体使用场景请斟酌使用。