ASP.NET Core在底层内置了一个依赖注入框架,经过依赖注入的方式注册服务、提供服务。依赖注入不只服务于ASP.NET Core自身,同时也是应用程序的服务提供者。编程
绝不夸张的说,ASP.NET Core经过依赖注入实现了各类服务对象的注册和建立,同时也实现了面向抽象的编程模式和编程体验,提高了应用程序的扩展性。api
今天,咱们普及一下ASP.NET Core中依赖注入的一些基本知识。mvc
1、服务的注册框架
咱们经过建立一个ASP.NET Core的项目,能够发如今Startup.cs 类中,有一个方法ConfigureServices,这个方法的注释是这样的:ide
This method gets called by the runtime. Use this method to add services to the container.函数
在ConfigureServices方法中咱们能够将经过ASP.NET Core内置的依赖注入框架实现服务的的注册。ui
这个方法有个参数:IServiceCollection,见名知意,服务集合。this
ASP.NET Core内置的依赖注入框架将服务注册信息存储到一个实现了IServiceCollection接口的对象中。默认状况下这个接口的实现类是ServiceCollection,如下是这个类的说明:spa
经过这个接口和类实现,咱们能够发现,注册服务其实就是将一个服务的ServiceDescriptor对象添加到ServiceCollection集合中。
例如:
public void ConfigureServices(IServiceCollection services) { services.Add(new ServiceDescriptor(typeof(IUserRepository), new UserRepository())); services.AddControllers(); }
ServiceDescriptor能够理解为对某个服务注册项的描述。ASP.NET Core的依赖注入容器IServiceProvider经过ServiceDescriptor的信息,动态建立服务的实例Instance.
咱们看一下这个ServiceDescriptor类:
有几个关键的属性:
1. ServiceType:服务的类型,例如服务接口的类型信息
2. ImplementationType:服务的实现类型,例如服务接口实现类的类型信息
3. ImplementationInstance:实现服务的实例,通常是服务单例模式场景下使用。 https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.dependencyinjection.servicedescriptor.-ctor?view=dotnet-plat-ext-3.1#Microsoft_Extensions_DependencyInjection_ServiceDescriptor__ctor_System_Type_System_Object_
4. Lifetime:服务生命周期:Scoped(同一个请求中同一个IServiceProvider提供的对象是同一个)、Singleton(单例)、Transient(每次从服务容器进行请求时建立)
5. ImplementationFactory 服务实例建立工厂,自定义的IServiceProvider服务提供容器
服务注册提供了一系列重载的方法,你们能够根据须要进行选择:
服务注册的过程当中,涉及到了服务的生命周期的概念,接下来咱们详细看一下。
2、服务生命周期
服务的生命周期设置,决定了服务提供容器IServiceProvider使用什么样的方式提供服务实例对象。正如上面第一章节所说的,
ASP.NET Core服务依赖注入框架,支持三种类型的服务生命周期:
其中:
Transient:暂时的,每次从服务容器进行请求时建立。 这种生存期适合轻量级、 无状态的服务。
Singleton:单一实例,在第一次请求时(或者在运行 Startup.ConfigureServices 而且使用服务注册指定实例时)建立的。每一个后续请求都使用相同的实例。
Scoped:范围内的,做用域生存期服务,以每一个客户端请求(链接)一次的方式建立。能够这么理解:同一个请求中同一个IServiceProvider提供的对象是同一个。
微软给了个例子不错:先注册服务,三种类型
public void ConfigureServices(IServiceCollection services) {
services.AddRazorPages();
services.AddScoped<IMyDependency, MyDependency>(); services.AddTransient<IOperationTransient, Operation>(); services.AddScoped<IOperationScoped, Operation>(); services.AddSingleton<IOperationSingleton, Operation>(); services.AddSingleton<IOperationSingletonInstance>(new Operation(Guid.Empty)); //OperationService depends on each of the other Operation types. services.AddTransient<OperationService, OperationService>(); }
第一个请求:
控制器操做: 暂时性:d233e165-f417-469b-a866-1cf1935d2518 做用域:5d997e2d-55f5-4a64-8388-51c4e3a1ad19 单一实例:01271bc1-9e31-48e7-8f7c-7261b040ded9 实例:00000000-0000-0000-0000-000000000000 OperationService 操做: 暂时性:c6b049eb-1318-4e31-90f1-eb2dd849ff64 做用域:5d997e2d-55f5-4a64-8388-51c4e3a1ad19 单一实例:01271bc1-9e31-48e7-8f7c-7261b040ded9 实例:00000000-0000-0000-0000-000000000000
第二个请求:
第二个请求: 控制器操做: 暂时性:b63bd538-0a37-4ff1-90ba-081c5138dda0 做用域:31e820c5-4834-4d22-83fc-a60118acb9f4 单一实例:01271bc1-9e31-48e7-8f7c-7261b040ded9 实例:00000000-0000-0000-0000-000000000000 OperationService 操做: 暂时性:c4cbacb8-36a2-436d-81c8-8c1b78808aaf 做用域:31e820c5-4834-4d22-83fc-a60118acb9f4 单一实例:01271bc1-9e31-48e7-8f7c-7261b040ded9 实例:00000000-0000-0000-0000-000000000000
你们能够根据实际的须要选择服务的生命周期,建立不一样类型的服务。
3、服务的消费
前面,咱们将服务注册到IServiceCollection,ASP.NET Core服务提供容器IServiceProvider就能够根据IServiceCollection 建立具体类型的服务对象了。
咱们先看一下IServiceProvider接口,能够发现:只有一个GetService方法。
咱们能够经过如下代码使用:
public static void Main(string[] args) { var builder = CreateHostBuilder(args); var host = builder.Build(); var userRepo = host.Services.GetService(typeof(IUserRepository)) as IUserRepository; userRepo.AddUser("user"); host.Run(); }
同时,咱们更多经常使用的是:
将服务经过ASP.NET Core依赖注入框架注入到控制器中
ASP.NET Core MVC 控制器经过构造函数显式请求依赖关系。即:经过构造函数注入服务的实现。
前面,咱们经过ConfigureServices注册了服务IUserRepository,在Controller这一层如何消费使用这个服务呢?答案就是在Controller构造函数中注入。
看一段示例代码:(HomeController的构造函数中,增长了一个参数IUserRepository)
public class HomeController : Controller { private readonly ILogger<HomeController> _logger; private IUserRepository _userRepository; public HomeController(ILogger<HomeController> logger, IUserRepository userRepository) { _logger = logger; _userRepository = userRepository; } public IActionResult Index() { _userRepository.AddUser(new User() { }); return View(); } public IActionResult Privacy() { return View(); } [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] public IActionResult Error() { return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier }); } }
同时,ASP.NET Core MVC 控制器支持经过注解FromServicesAttribute, 将服务直接注入到Action方法中,而无需使用构造函数注入:
public IActionResult Index([FromServices] IUserRepository userRepository) { userRepository.AddUser(new User() { }); return View(); }
ASP.NET Core除了支持将服务注入到控制器,同时还支持将服务依赖注入到视图,能够参考如下连接:
https://docs.microsoft.com/zh-cn/aspnet/core/mvc/views/dependency-injection?view=aspnetcore-3.0
以上是对ASP.NET Core依赖注入框架的研究,分享给你们。
周国庆
2020/4/12