-
一、什么是依赖注入
-
二、.NET Core DI
-
三、DI在ASP.NET Core中的应用
-
四、如何替换其它的Ioc容器
一、什么是依赖注入(Denpendency Injection)
1.1依赖
1
2
3
4
5
|
public
AccountController(ILoginService<ApplicationUser> loginService)
{
_loginService = loginService;
}
|
// 用Redis来替换原来的EF登录 var controller = new AccountController(new RedisLoginService()); controller.Login(userName, password);
1.4 何为容器
二、.NET Core DI
2.1 实例的注册
1
2
3
4
|
var
serviceCollection =
new
ServiceCollection()
.AddTransient<ILoginService, EFLoginService>()
.AddSingleton<ILoginService, EFLoginService>()
.AddScoped<ILoginService, EFLoginService>();
|
1
2
3
|
public
interface
IServiceCollection : IList<ServiceDescriptor>
{
}
|
我们上面的AddTransient、AddSignletone和Scoped方法是IServiceCollection的扩展方法, 都是往这个List里面添加ServiceDescriptor。
1
2
3
4
5
6
7
8
9
10
11
|
private
static
IServiceCollection Add(
IServiceCollection collection,
Type serviceType,
Type implementationType,
ServiceLifetime lifetime)
{
var
descriptor =
new
ServiceDescriptor(serviceType, implementationType, lifetime);
collection.Add(descriptor);
return
collection;
}
|
2.2 实例的生命周期之单例
1
2
3
4
5
6
|
public
enum
ServiceLifetime
{
Singleton,
Scoped,
Transient
}
|
1
2
3
4
5
6
7
|
public
interface
IOperation
{
Guid OperationId {
get
; }
}
public
interface
IOperationSingleton : IOperation { }
public
interface
IOperationTransient : IOperation{}
public
interface
IOperationScoped : IOperation{}
|
我们的 Operation实现很简单,可以在构造函数中传入一个Guid进行赋值,如果没有的话则自已New一个 Guid。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
public
class
Operation :
IOperationSingleton,
IOperationTransient,
IOperationScoped
{
private
Guid _guid;
public
Operation() {
_guid = Guid.NewGuid();
}
public
Operation(Guid guid)
{
_guid = guid;
}
public
Guid OperationId => _guid;
}
|
在程序内我们可以多次调用ServiceProvider的GetService方法,获取到的都是同一个实例。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
var
services =
new
ServiceCollection();
// 默认构造
services.AddSingleton<IOperationSingleton, Operation>();
// 自定义传入Guid空值
services.AddSingleton<IOperationSingleton>(
new
Operation(Guid.Empty));
// 自定义传入一个New的Guid
services.AddSingleton <IOperationSingleton>(
new
Operation(Guid.NewGuid()));
var
provider = services.BuildServiceProvider();
// 输出singletone1的Guid
var
singletone1 = provider.GetService<IOperationSingleton>();
Console.WriteLine($
"signletone1: {singletone1.OperationId}"
);
// 输出singletone2的Guid
var
singletone2 = provider.GetService<IOperationSingleton>();
Console.WriteLine($
"signletone2: {singletone2.OperationId}"
);
Console.WriteLine($
"singletone1 == singletone2 ? : { singletone1 == singletone2 }"
);
|
我们对IOperationSingleton注册了三次,最后获取两次,大家要注意到我们获取到的始终都是我们最后一次注册的那个给了一个Guid的实例,前面的会被覆盖。
2.3 实例生命周期之Tranisent
这次我们获取到的IOperationTransient为两个不同的实例。
2.4 实例生命周期之Scoped
1
2
3
4
|
var
services =
new
ServiceCollection()
.AddScoped<IOperationScoped, Operation>()
.AddTransient<IOperationTransient, Operation>()
.AddSingleton<IOperationSingleton, Operation>();
|
接下来我们用ServiceProvider.CreateScope方法创建一个Scope
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
var
provider = services.BuildServiceProvider();
using
(
var
scope1 = provider.CreateScope())
{
var
p = scope1.ServiceProvider;
var
scopeobj1 = p.GetService<IOperationScoped>();
var
transient1 = p.GetService<IOperationTransient>();
var
singleton1 = p.GetService<IOperationSingleton>();
var
scopeobj2 = p.GetService<IOperationScoped>();
var
transient2 = p.GetService<IOperationTransient>();
var
singleton2 = p.GetService<IOperationSingleton>();
Console.WriteLine(
$
"scope1: { scopeobj1.OperationId },"
+
$
"transient1: {transient1.OperationId}, "
+
$
"singleton1: {singleton1.OperationId}"
);
Console.WriteLine($
"scope2: { scopeobj2.OperationId }, "
+
$
"transient2: {transient2.OperationId}, "
+
$
"singleton2: {singleton2.OperationId}"
);
}
|
接下来
scope1: 200d1e63-d024-4cd3-88c9-35fdf5c00956,
transient1: fb35f570-713e-43fc-854c-972eed2fae52,
singleton1: da6cf60f-670a-4a86-8fd6-01b635f74225
scope2: 200d1e63-d024-4cd3-88c9-35fdf5c00956, transient2: 2766a1ee-766f-4116-8a48-3e569de54259, singleton2: da6cf60f-670a-4a86-8fd6-01b635f74225
如果再创建一个新的Scope运行,
scope1: 29f127a7-baf5-4ab0-b264-fcced11d0729,
transient1: 035d8bfc-c516-44a7-94a5-3720bd39ce57,
singleton1: da6cf60f-670a-4a86-8fd6-01b635f74225
scope2: 29f127a7-baf5-4ab0-b264-fcced11d0729, transient2: 74c37151-6497-4223-b558-a4ffc1897d57, singleton2: da6cf60f-670a-4a86-8fd6-01b635f74225
三、DI在ASP.NET Core中的应用
3.1在Startup类中初始化
1
2
3
4
5
6
|
public
void
ConfigureServices(IServiceCollection services)
{
services.AddTransient<ILoginService<ApplicationUser>,
EFLoginService>();
services.AddMvc();
)
|
ASP.NET Core的一些组件已经提供了一些实例的绑定,像AddMvc就是Mvc Middleware在 IServiceCollection上添加的扩展方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
public
static
IMvcBuilder AddMvc(
this
IServiceCollection services)
{
if
(services ==
null
)
{
throw
new
ArgumentNullException(nameof(services));
}
var
builder = services.AddMvcCore();
builder.AddApiExplorer();
builder.AddAuthorization();
AddDefaultFrameworkParts(builder.PartManager);
...
}
|
3.2 Controller中使用
1
2
3
4
5
6
|
private
ILoginService<ApplicationUser> _loginService;
public
AccountController(
ILoginService<ApplicationUser> loginService)
{
_loginService = loginService;
}
|
我们只要在控制器的构造函数里面写了这个参数,ServiceProvider就会帮我们注入进来。这一步是在Mvc初始化控制器的时候完成的,我们后面再介绍到Mvc的时候会往细里讲。
3.3 View中使用
1
2
3
4
5
6
7
8
9
10
|
@
using
MilkStone.Services;
@model MilkStone.Models.AccountViewModel.LoginViewModel
@inject ILoginService<ApplicationUser> loginService
<!DOCTYPE html>
<html xmlns=
"http://www.w3.org/1999/xhtml"
>
<head></head>
<body>
@loginService.GetUserName()
</body>
</html>
|
3.4 通过 HttpContext来获取实例
1
|
HttpContext.RequestServices.GetService<ILoginService<ApplicationUser>>();
|
四、如何替换其它的Ioc容器
1
2
3
|
builder.RegisterGeneric(
typeof
(LoggingBehavior<,>)).As(
typeof
(IPipelineBehavior<,>));
builder.RegisterGeneric(
typeof
(ValidatorBehavior<,>)).As(
typeof
(IPipelineBehavior<,>));
|
这会给我们的初始化带来一些便利性,我们来看看如何替换Autofac到ASP.NET Core。我们只需要把Startup类里面的 ConfigureService的 返回值从 void改为 IServiceProvider即可。而返回的则是一个AutoServiceProvider。
1
2
3
4
5
6
7
8
9
10
11
12
|
public
IServiceProvider ConfigureServices(
IServiceCollection services){
services.AddMvc();
// Add other framework services
// Add Autofac
var
containerBuilder =
new
ContainerBuilder();
containerBuilder.RegisterModule<DefaultModule>();
containerBuilder.Populate(services);
var
container = containerBuilder.Build();
return
new
AutofacServiceProvider(container);
}
|
4.1 有何变化
来源:oschina
链接:https://my.oschina.net/u/4278795/blog/4281712