Microsoft.Extensions.DependencyInjection 是 .NET Core 中用于依赖注入的库。
但是它也支持 .NET Framework。
快速开始
1 2 3 4 5 6
| IServiceProvider serviceProvider = new ServiceCollection() .AddTransient<IService, Service>() .BuildServiceProvider();
var service = serviceProvider.GetService<IService>(); service.PrintMessage();
|
IServiceCollection:用于注册应用程序所需的服务。并通过BuildServiceProvider方法构建ServiceProvider。
IServiceProvider:提供服务的容器。构建ServiceProvider时,IServiceCollection中注册的所有服务都会被实例化,并按照其生命周期进行管理。
注册服务
1 2 3
| AddSingleton<IService, Service>(); AddScoped<IService, Service>(); AddTransient<IService, Service>();
|
生命周期内容可以看下一节。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| private static void Foo() { var serviceCollection = new ServiceCollection(); var serviceProvider = serviceCollection .AddKeyedTransient<IServiceA, ServiceA1>("A1") .AddKeyedTransient<IServiceA, ServiceA2>("A2") .BuildServiceProvider();
var obj = serviceProvider.GetKeyedService<IServiceA>("A1"); obj.Say();
obj = serviceProvider.GetKeyedService<IServiceA>("A2"); obj.Say(); }
|
参数Key是一个object类型,所以也可以是其他类型作为 Key。
生命周期
Singleton
- 单例。每次请求都会返回相同的实例。
ServiceProvider会引用该实例。
1 2 3 4 5 6 7 8 9 10 11 12
| private static void Foo() { var serviceProvider = new ServiceCollection() .AddSingleton<IService, Service>() .BuildServiceProvider();
var service = serviceProvider.GetService<IService>(); Debug.WriteLine($"{service.GetHashCode()}");
service = serviceProvider.GetService<IService>(); Debug.WriteLine($"{service.GetHashCode()}"); }
|
两次输出相同的 HashCode。
1
| AddSingleton(new Service());
|
Scoped
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| private static void Foo() { var serviceProvider = new ServiceCollection() .AddScoped<IService, Service>() .BuildServiceProvider();
using (var scope = serviceProvider.CreateScope()) { var s1 = scope.ServiceProvider.GetService<IService>(); Debug.WriteLine($"{s1.GetHashCode()}");
var s2 = scope.ServiceProvider.GetService<IService>(); Debug.WriteLine($"{s2.GetHashCode()}"); }
using (var scope = serviceProvider.CreateScope()) { var s1 = scope.ServiceProvider.GetService<IService>(); Debug.WriteLine($"{s1.GetHashCode()}");
var s2 = scope.ServiceProvider.GetService<IService>(); Debug.WriteLine($"{s2.GetHashCode()}"); } }
|
如果不在作用域内请求也是可以的,但是会产生单例的效果:
1 2 3 4 5 6 7 8 9 10 11 12
| private static void Foo() { var serviceProvider = new ServiceCollection() .AddScoped<IService, Service>() .BuildServiceProvider();
var s3 = serviceProvider.GetService<IService>(); Debug.WriteLine($"{s3.GetHashCode()}");
var s4 = serviceProvider.GetService<IService>(); Debug.WriteLine($"{s4.GetHashCode()}"); }
|
在作用域外请求被认为是反模式,为了约束这种错误的用法,可以在BuildServiceProvider方法中传入validateScopes = true。
1 2 3 4 5 6 7 8
| private static void Foo() { var serviceProvider = new ServiceCollection() .AddScoped<IService, Service>() .BuildServiceProvider(validateScopes: true);
var s3 = serviceProvider.GetService<IService>(); }
|
错误的用法将会抛出一个InvalidOperationException异常。
Transient
1 2 3 4 5 6 7 8 9 10 11 12
| private static void Foo() { var serviceProvider = new ServiceCollection() .AddTransient<IServiceA, ServiceA>() .BuildServiceProvider();
var s1 = serviceProvider.GetService<IServiceA>(); Debug.WriteLine($"{s1.GetHashCode()}");
var s2 = serviceProvider.GetService<IServiceA>(); Debug.WriteLine($"{s2.GetHashCode()}"); }
|
每次请求都是新的实例。
注入
Microsoft.Extensions.DependencyInjection仅有构造函数注入。并不支持属性注入。
构造注入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| AddTransient<IServiceA, ServiceA>(); AddTransient<IServiceB, ServiceB>();
public class ServiceC : IServiceC { public ServiceC(IServiceA a) { Debug.WriteLine("1"); }
public ServiceC(IServiceA a, IServiceB b) { Debug.WriteLine("2"); } public ServiceC(int n1, int n2, int n3) {} }
|
总结
Microsoft.Extensions.DependencyInjection很轻量,它并不是一个大而全的 IoC 容器。对于复杂的依赖注入场景来说功能有限。为了满足更高级的需求,可以使用其他第三方容器。
它只是微软官方一系列扩展包中的一个公共模块,是为了服务其他扩展的。
以下是其他部分扩展:
Microsoft.Extensions.Logging:提供了日志记录功能的扩展,可以与各种日志记录器(如Console、Debug、File、EventSource等)集成。
Microsoft.Extensions.Configuration:提供了配置管理功能的扩展,可以从不同的配置源(如JSON、XML、环境变量等)读取和解析配置信息。
Microsoft.Extensions.Caching:提供了缓存功能的扩展,可以将数据缓存在内存、分布式缓存(如Redis)中,并提供灵活的缓存策略。
Microsoft.Extensions.Options:提供了配置选项功能的扩展,可以轻松地将配置选项注入到应用程序中,并进行验证和转换。
Microsoft.Extensions.Diagnostics.HealthChecks:提供了应用程序健康检查功能的扩展,可以检查应用程序的各种依赖和状态。
官方的扩展远不止这几个,更多的可以直接去 nuget 网站搜索前缀Microsoft.Extensions即可。便民链接
这些包的设计目标是提供可插拔的模块,以便开发人员根据项目需求选择适当的功能和扩展。
参考
Exploring the Microsoft.Extensions.DependencyInjection Machinery