接上文,我们来看看NETCore下DI的使用。我们这里其实主要是讨论ASP.NETCore,因为我们最主要是用NETCore来实现WebAPI。
1. 注册和获取服务
ASP.NETCore框架核心就是依赖注入,它的服务容器就是IServiceCollection
,大家可以理解为一个服务注册的字典,Key是接口,Value是注册到这个接口上的接口实现,重复注册是会覆盖前一次的注册。
大家可以单步跟踪一下IServiceCollection的值,可以看到执行AddMvc之前里面有63个值,执行AddMvc后就变成200多个,说明AddMvc是相当于执行了100多次服务的注入。我们如果自己要注入一个服务的话,类似以下代码:
services.AddSingleton<Interface1, Class1>();
services.AddTransient<Interface2, Class2>();
services.AddScoped<Interface3, Class3>();
服务注册之后,如何根据接口来获取实例了,通常二种方式:
第一种:通过IServiceProvider
接口或通过IServiceCollection来获取ServiceProvider实例
var provider = services.BuildServiceProvider();
var class1 = provider.GetService<Interface1>();
Console.WriteLine(class1.function1());
public ValuesController(IServiceProvider provider)
{
Console.WriteLine(i1.function1());
Console.WriteLine(i2.function2());
Console.WriteLine(i3.function3());
var test = provider.GetService<TestScopeClass>();
}
第二种:直接在构造函数里把接口作为参数
public ValuesController(Interface1 i1, Interface2 i2, Interface3 i3)
{
Console.WriteLine(i1.function1());
Console.WriteLine(i2.function2());
Console.WriteLine(i3.function3());
}
2. 生命周期
每个注入的实例都是有生命周期的,生命周期就三种
- AddSingleton : 在整个应用生命周期里都是唯一
- AddTransient:每次获取一次服务就创建一个实例
- AddScoped:在我们自定义的Scope内的生命周期,在Scope内是唯一
前二种比较简单,Scope的说一下,参考例子:
using (var scope1 = provider.CreateScope())
{
var p = scope1.ServiceProvider;
var scopeobj1 = p.GetService<Interface3>();
var transient1 = p.GetService<Interface2>();
var singleton1 = p.GetService<Interface1>();
var scopeobj2 = p.GetService<Interface3>();
var transient2 = p.GetService<Interface2>();
var singleton2 = p.GetService<Interface1>();
Console.WriteLine(
$"scope1: { scopeobj1.function3() }," +
$"transient1: {transient1.function2()}, " +
$"singleton1: {singleton1.function1()}");
Console.WriteLine($"scope2: { scopeobj2.function3() }, " +
$"transient2: {transient2.function2()}, " +
$"singleton2: {singleton2.function1()}");
}
运行这个函数二遍,我们看结果,可以看出在不同的Scope下对象不一样,但是在一个Scope下获取二次对象是一样的。
image.png
这个例子不是那么直观,在ASP.NETCore下最常用的其实是Http的请求处理,每次请求都会创建一个新的Scope里,这样的话,这个请求内所有scope的注入对象都只有一份,比如DbContext对象在一次请求里是不会变的,这样确保一次请求对数据库的操作不会错乱。但是多次请求就不一样了。我们看看另外一个例子,在controller里的例子:
public class ValuesController : Controller
{
public ValuesController(Interface1 i1, Interface2 i2, Interface3 i3,IServiceProvider provider)
{
Console.WriteLine(i1.function1());
Console.WriteLine(i2.function2());
Console.WriteLine(i3.function3());
var test = provider.GetService<Interface3>();
Console.WriteLine(test.function3());
}
再看看执行的结果:
image.png
可以看出http请求了二次,每次Class3的对象都不一样,但是在一个请求里多次获取对象是一样的。
示例代码参考Github
网友评论