[ASP.NET Core 3框架揭秘] 依赖注入[7]:服务消费
含服务注册信息的IServiceCollection集合最终被用来创建作为依赖注入容器的IServiceProvider对象。当需要消费某个服务实例的时候,我们只需要指定服务类型调用IServiceProvider的GetService方法即可,IServiceProvider对象就会根据对应的服务注册提供所需的服务实例。
一、IServiceProvider
如下面的代码片段所示,IServiceProvider接口定义了唯一的GetService方法根据指定的类型来提供对应的服务实例。当利用包含服务注册的IServiceCollection对象创建出IServiceProvider对象之后,我们只需要将服务注册的服务类型(对应于ServiceDescriptor的ServiceType属性)作为参数调用GetService方法,该方法就能根据服务注册信息为我们提供对应的服务实例。
public interface IServiceProvider { object GetService(Type serviceType); }
针对IServiceProvider对象的创建体现在IServiceCollection接口的三个BuildServiceProvider扩展方法重载上。如下的代码片段所示,这三个扩展方法提供的都是一个类型为ServiceProvider的对象,该对象根据提供的配置选项来创建。配置选项类型ServiceProviderOptions提供了两个属性,其中ValidateScopes属性表示是否需要开启针对服务范围的验证,而ValidateOnBuild属性则表示是否需要预先检验作为服务注册的每个ServiceDescriptor对象能否提供对应的服务实例。默认情况下这两种类型的检验都是关闭的。
public class ServiceProviderOptions { public bool ValidateScopes { get; set; } public bool ValidateOnBuild { get; set; } internal static readonly ServiceProviderOptions Default = new ServiceProviderOptions(); } public static class ServiceCollectionContainerBuilderExtensions { public static ServiceProvider BuildServiceProvider( this IServiceCollection services) => BuildServiceProvider(services, ServiceProviderOptions.Default); public static ServiceProvider BuildServiceProvider( this IServiceCollection services, bool validateScopes) => services.BuildServiceProvider(new ServiceProviderOptions { ValidateScopes = validateScopes }); public static ServiceProvider BuildServiceProvider( this IServiceCollection services, ServiceProviderOptions options) => new ServiceProvider(services, options); }
虽然调用IServiceCollection的BuildServiceProvider扩展方法返回总是一个ServiceProvider对象,但是我并不打算详细介绍这个类型,这是因为ServiceProvider涉及到一系列内部类型和接口,并且实现在该类型中针对服务实例的提供机制一直在不断的变化,而且这个变化趋势在未来版本更替过程中可能还将继续下去。
除了定义在IServiceProvider接口中的GetService方法,该接口还具有如下这些扩展方法来提供服务实例。GetService<T>方法以泛型参数的形式指定了服务类型,返回的服务实例也会作对应的类型转换。如果指定服务类型的服务注册不存在,GetService方法会返回Null,如果调用GetRequiredService或者GetRequiredService<T>方法则会抛出一个InvalidOperationException类型的异常。如果所需的服务实例是必需的,我们一般会调用这两个扩展方法。
public static class ServiceProviderServiceExtensions { public static T GetService<T>(this IServiceProvider provider); public static T GetRequiredService<T>(