在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
之前梳理过依赖注入和控制反转,总结来说,控制反转是一种思想,依赖注入是一种设计模式,控制反转的思想可以利用依赖注入的设计模式实现,反射是依赖注入实现过程的核心技术。这里不在详述依赖注入、控制反转和反射。本文的重心是梳理依赖注入设计模式在ASP.NET Core的应用。 ASP.NET Core 支持依赖关系注入 (DI) 软件设计模式,这是一种在类及其依赖关系之间实现控制反转 (IoC) 的技术。上文中也提到利用DI要做的两个功能是:
那么在ASP.NET Core中是如何实现这两个功能的呢? 1、注册服务的实现就从startup.cs中的ConfigureServices方法说起,先来看下定义: public virtual void ConfigureServices (Microsoft.Extensions.DependencyInjection.IServiceCollection services); 这里涉及到一个概念IServiceCollection,先来看下IServiceCollection的命名空间和定义: namespace Microsoft.Extensions.DependencyInjection { /// <summary> /// Specifies the contract for a collection of service descriptors. /// </summary> public interface IServiceCollection : IList<ServiceDescriptor> { } } 发现又涉及到一个概念ServiceDescriptor,这里不对ServiceDescriptor展开,总结来说,ServiceDescriptor对象用来描述一种服务,包括该服务的类型、实现和生存期。所以说IServiceCollection是为ServiceDescriptor集合指定协定,即IServiceCollection用来管理ServiceDescriptor集合。先来看下IServiceCollection的实现ServiceCollection: namespace Microsoft.Extensions.DependencyInjection { /// <summary> /// Default implementation of <see cref="IServiceCollection"/>. /// </summary> public class ServiceCollection : IServiceCollection { private readonly List<ServiceDescriptor> _descriptors = new List<ServiceDescriptor>(); /// <inheritdoc /> public int Count => _descriptors.Count; /// <inheritdoc /> public bool IsReadOnly => false; /// <inheritdoc /> public ServiceDescriptor this[int index] { get { return _descriptors[index]; } set { _descriptors[index] = value; } } /// <inheritdoc /> public void Clear() { _descriptors.Clear(); } /// <inheritdoc /> public bool Contains(ServiceDescriptor item) { return _descriptors.Contains(item); } /// <inheritdoc /> public void CopyTo(ServiceDescriptor[] array, int arrayIndex) { _descriptors.CopyTo(array, arrayIndex); } /// <inheritdoc /> public bool Remove(ServiceDescriptor item) { return _descriptors.Remove(item); } 接下来解析下ServiceCollection代码,代码中定义了ServiceDescriptor的集合_descriptors : private readonly List<ServiceDescriptor> _descriptors = new List<ServiceDescriptor>(); 然后就是对ServiceDescriptor集合进行增删改查相关的操作,因此我们可以认为ServiceDescriptor对象就是一个服务,ServiceDescriptor集合就是服务容器,IServiceCollection的实现类ServiceCollection提供了对服务容器进行注册、移除等相关的管理。这里就算是完成了依赖注入需要完成的功能1:注册服务。 2、注入服务的实现上边介绍了ASP.NET Core利用IServiceCollection和ServiceDescriptor完成了服务的注册,那么服务的注入如何实现呢?如何在需要的地方能够注入相应的服务呢? IServiceCollection的实现类ServiceCollection提供了注册服务的相关方法,那么有没有提供服务注入的方法呢?先来看下ServiceCollection的扩展方法: namespace Microsoft.Extensions.DependencyInjection { /// <summary> /// Extension methods for building a <see cref="ServiceProvider"/> from an <see cref="IServiceCollection"/>. /// </summary> public static class ServiceCollectionContainerBuilderExtensions { /// <summary> /// Creates a <see cref="ServiceProvider"/> containing services from the provided <see cref="IServiceCollection"/>. /// </summary> /// <param name="services">The <see cref="IServiceCollection"/> containing service descriptors.</param> /// <returns>The <see cref="ServiceProvider"/>.</returns> public static ServiceProvider BuildServiceProvider(this IServiceCollection services) { return BuildServiceProvider(services, ServiceProviderOptions.Default); } /// <summary> /// Creates a <see cref="ServiceProvider"/> containing services from the provided <see cref="IServiceCollection"/> /// optionally enabling scope validation. /// </summary> /// <param name="services">The <see cref="IServiceCollection"/> containing service descriptors.</param> /// <param name="validateScopes"> /// <c>true</c> to perform check verifying that scoped services never gets resolved from root provider; otherwise <c>false</c>. /// </param> /// <returns>The <see cref="ServiceProvider"/>.</returns> public static ServiceProvider BuildServiceProvider(this IServiceCollection services, bool validateScopes) { return services.BuildServiceProvider(new ServiceProviderOptions { ValidateScopes = validateScopes }); } /// <summary> /// Creates a <see cref="ServiceProvider"/> containing services from the provided <see cref="IServiceCollection"/> /// optionally enabling scope validation. /// </summary> /// <param name="services">The <see cref="IServiceCollection"/> containing service descriptors.</param> /// <param name="options"> /// Configures various service provider behaviors. /// </param> /// <returns>The <see cref="ServiceProvider"/>.</returns> public static ServiceProvider BuildServiceProvider(this IServiceCollection services, ServiceProviderOptions options) { if (services == null) { throw new ArgumentNullException(nameof(services)); } if (options == null) { throw new ArgumentNullException(nameof(options)); } return new ServiceProvider(services, options); } } } ServiceCollection扩展方法提供了构建IServiceProvider的方法,先来了解下IServiceProvider的定义: namespace System { public interface IServiceProvider { object GetService(Type serviceType); } } IServiceProvider提供给了一个根据类型获取对象的功能。 读到这里先来梳理下,算是承上启下吧:上边说道ServiceCollection提供了管理服务集合的方法,即注册服务;ServiceCollection的扩展方法提供了构建IServiceProvider的方法,而IServiceProvider提供给了一个根据类型获取对象的功能。 理论上说Asp.net core利用IServiceCollection、ServiceDescriptor和IServiceProvider实现了注册服务和注入服务的功能。 那么这里有个疑问?IServiceProvider是如何实现注入服务的呢?接下来我们分析下IServiceProvider实现类ServiceProvider 的源码: namespace Microsoft.Extensions.DependencyInjection { /// <summary> /// The default IServiceProvider. /// </summary> public sealed class ServiceProvider : IServiceProvider, IDisposable, IServiceProviderEngineCallback, IAsyncDisposable { private readonly IServiceProviderEngine _engine; private readonly CallSiteValidator _callSiteValidator; internal ServiceProvider(IEnumerable<ServiceDescriptor> serviceDescriptors, ServiceProviderOptions options) { IServiceProviderEngineCallback callback = null; if (options.ValidateScopes) { callback = this; _callSiteValidator = new CallSiteValidator(); } switch (options.Mode) { case ServiceProviderMode.Default: #if !NETCOREAPP _engine = new DynamicServiceProviderEngine(serviceDescriptors, callback); #else if (RuntimeFeature.IsSupported("IsDynamicCodeCompiled")) { _engine = new DynamicServiceProviderEngine(serviceDescriptors, callback); } else { // Don't try to compile Expressions/IL if they are going to get interpreted _engine = new RuntimeServiceProviderEngine(serviceDescriptors, callback); } #endif break; case ServiceProviderMode.Dynamic: _engine = new DynamicServiceProviderEngine(serviceDescriptors, callback); break; case ServiceProviderMode.Runtime: _engine = new RuntimeServiceProviderEngine(serviceDescriptors, callback); break; #if IL_EMIT case ServiceProviderMode.ILEmit: _engine = new ILEmitServiceProviderEngine(serviceDescriptors, callback); break; #endif case ServiceProviderMode.Expressions: _engine = new ExpressionsServiceProviderEngine(serviceDescriptors, callback); break; default: throw new NotSupportedException(nameof(options.Mode)); } if (options.ValidateOnBuild) { List<Exception> exceptions = null; foreach (var serviceDescriptor in serviceDescriptors) { try { _engine.ValidateService(serviceDescriptor); } catch (Exception e) { exceptions = exceptions ?? new List<Exception>(); exceptions.Add(e); } } if (exceptions != null) { throw new AggregateException("Some services are not able to be constructed", exceptions.ToArray()); } } } /// <summary> /// Gets the service object of the specified type. /// </summary> /// <param name="serviceType">The type of the service to get.</param> /// <returns>The service that was produced.</returns> public object GetService(Type serviceType) => _engine.GetService(serviceType); /// <inheritdoc /> public void Dispose() { _engine.Dispose(); } void IServiceProviderEngineCallback.OnCreate(ServiceCallSite callSite) { _callSiteValidator.ValidateCallSite(callSite); } void IServiceProviderEngineCallback.OnResolve(Type serviceType, IServiceScope scope) { _callSiteValidator.ValidateResolution(serviceType, scope, _engine.RootScope); } /// <inheritdoc/> public ValueTask DisposeAsync() { return _engine.DisposeAsync(); } } } 从上面代码中我们看到ServiceProvider实现了GetService方法: public object GetService(Type serviceType) => _engine.GetService(serviceType); 但是里面涉及到一个对象_engine,它是什么呢?我们接着分析_engine初始化的代码: internal ServiceProvider(IEnumerable<ServiceDescriptor> serviceDescriptors, ServiceProviderOptions options) { IServiceProviderEngineCallback callback = null; if (options.ValidateScopes) { callback = this; _callSiteValidator = new CallSiteValidator(); } switch (options.Mode) { case ServiceProviderMode.Default: #if !NETCOREAPP _engine = new DynamicServiceProviderEngine(serviceDescriptors, callback); #else if (RuntimeFeature.IsSupported("IsDynamicCodeCompiled")) { _engine = new DynamicServiceProviderEngine(serviceDescriptors, callback); } else { // Don't try to compile Expressions/IL if they are going to get interpreted _engine = new RuntimeServiceProviderEngine(serviceDescriptors, callback); } #endif break; case ServiceProviderMode.Dynamic: _engine = new DynamicServiceProviderEngine(serviceDescriptors, callback); break; case ServiceProviderMode.Runtime: _engine = new RuntimeServiceProviderEngine(serviceDescriptors, callback); break; #if IL_EMIT case ServiceProviderMode.ILEmit: _engine = new ILEmitServiceProviderEngine(serviceDescriptors, callback); break; #endif case ServiceProviderMode.Expressions: _engine = new ExpressionsServiceProviderEngine(serviceDescriptors, callback); break; default: throw new NotSupportedException(nameof(options.Mode)); } if (options.ValidateOnBuild) { List<Exception> exceptions = null; foreach (var serviceDescriptor in serviceDescriptors) { try { _engine.ValidateService(serviceDescriptor); } catch (Exception e) { exceptions = exceptions ?? new List<Exception>(); exceptions.Add(e); } } if (exceptions != null) { throw new AggregateException("Some services are not able to be constructed", exceptions.ToArray()); } } } 从上面代码可以看出_engine是一个与ServiceDescriptor关联的IServiceProviderEngine对象。而且根据ServiceProviderMode枚举内容的不同,_engine有不同的初始化方案,下面看下ServiceProviderMode的枚举值: namespace Microsoft.Extensions.DependencyInjection { internal enum ServiceProviderMode { Default, Dynamic, Runtime, Expressions, ILEmit } } 这里有个疑问:IServiceProviderEngine是什么?为什么_engine有不同的初始化方案?ServiceProviderMode中的方案都代表着什么? 为了解决上边的疑问,接下来探究下IServiceProviderEngine的定义: namespace Microsoft.Extensions.DependencyInjection.ServiceLookup { internal interface IServiceProviderEngine : IServiceProvider, IDisposable, IAsyncDisposable { IServiceScope RootScope { get; } void ValidateService(ServiceDescriptor descriptor); } } 好像看不出来什么,接下来看下IServiceProviderEngine的实现类ServiceProviderEngine: namespace Microsoft.Extensions.DependencyInjection.ServiceLookup { internal abstract class ServiceProviderEngine : IServiceProviderEngine, IServiceScopeFactory { private readonly IServiceProviderEngineCallback _callback; private readonly Func<Type, Func<ServiceProviderEngineScope, object>> _createServiceAccessor; private bool _disposed; protected ServiceProviderEngine(IEnumerable<ServiceDescriptor> serviceDescriptors, IServiceProviderEngineCallback callback) { _createServiceAccessor = CreateServiceAccessor; _callback = callback; Root = new ServiceProviderEngineScope(this); RuntimeResolver = new CallSiteRuntimeResolver(); CallSiteFactory = new CallSiteFactory(serviceDescriptors); CallSiteFactory.Add(typeof(IServiceProvider), new ServiceProviderCallSite()); CallSiteFactory.Add(typeof(IServiceScopeFactory), new ServiceScopeFactoryCallSite()); RealizedServices = new ConcurrentDictionary<Type, Func<ServiceProviderEngineScope, object>>(); } internal ConcurrentDictionary<Type, Func<ServiceProviderEngineScope, object>> RealizedServices { get; } internal CallSiteFactory CallSiteFactory { get; } protected CallSiteRuntimeResolver RuntimeResolver { get; } public ServiceProviderEngineScope Root { get; } public IServiceScope RootScope => Root; public void ValidateService(ServiceDescriptor descriptor) { if (descriptor.ServiceType.IsGenericType && !descriptor.ServiceType.IsConstructedGenericType) { return; } try { var callSite = CallSiteFactory.GetCallSite(descriptor, new CallSiteChain()); if (callSite != null) { _callback?.OnCreate(callSite); } } catch (Exception e) { throw new InvalidOperationException($"Error while validating the service descriptor '{descriptor}': {e.Message}", e); } } public object GetService(Type serviceType) => GetService(serviceType, Root); protected abstract Func<ServiceProviderEngineScope, object> RealizeService(ServiceCallSite callSite); public void Dispose() { _disposed = true; Root.Dispose(); } public ValueTask DisposeAsync() { _disposed = true; return Root.DisposeAsync(); } internal object GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope) { if (_disposed) { ThrowHelper.ThrowObjectDisposedException(); } var realizedService = RealizedServices.GetOrAdd(serviceType, _createServiceAccessor); _callback?.OnResolve(serviceType, serviceProviderEngineScope); DependencyInjectionEventSource.Log.ServiceResolved(serviceType); return realizedService.Invoke(serviceProviderEngineScope); } public IServiceScope CreateScope() { if (_disposed) { ThrowHelper.ThrowObjectDisposedException(); } return new ServiceProviderEngineScope(this); } private Func<ServiceProviderEngineScope, object> CreateServiceAccessor(Type serviceType) { var callSite = CallSiteFactory.GetCallSite(serviceType, new CallSiteChain()); if (callSite != null) { DependencyInjectionEventSource.Log.CallSiteBuilt(serviceType, callSite); _callback?.OnCreate(callSite); return RealizeService(callSite); } return _ => null; } } } 具体分析下上边的代码:
从上述代码中看出,ServiceProviderEngine构造函数中调用了CreateServiceAccessor方法,在CreateServiceAccessor方法中又调用了RealizeService方法,而ServiceProviderEngine中的RealizeService方法是个抽象方法,具体的实现体现了_engine初始化的方案:
这四个类都重写了RealizeService方法,但是他们的目的都是一样的:编译一个类型为Func <ServiceProvider,object>的委托,并被缓存起来服务于后续针对同一个类型的服务提供请求,该委托对象与对应服务类型之间的映射关系就保存在RealizedServices属性中。简单的说RealizeService方法就是将对注册的服务做一个类型映射关系,然后将该关系保存在RealizedServices字典中,RealizedServices是一个ConcurrentDictionary字典对象。 现在又回归到前面说到的ServiceProvider是如何实现注入服务的:先来看下RealizedServices的定义: internal ConcurrentDictionary<Type, Func<ServiceProviderEngineScope, object>> RealizedServices { get; } 用于存储类型与Func<ServiceProviderEngineScope, object>委托的关系,而ServiceProviderEngineScope继承了IServiceProvider,并且ServiceProviderEngineScope类中实现了GetService方法: public object GetService(Type serviceType) { if (_disposed) { ThrowHelper.ThrowObjectDisposedException(); } return Engine.GetService(serviceType, this); } 而Engine调用ServiceProviderEngine中GetService方法,进而从RealizedServices获取相应的服务。 internal object GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope) { if (_disposed) { ThrowHelper.ThrowObjectDisposedException(); } var realizedService = RealizedServices.GetOrAdd(serviceType, _createServiceAccessor); _callback?.OnResolve(serviceType, serviceProviderEngineScope); DependencyInjectionEventSource.Log.ServiceResolved(serviceType); return realizedService.Invoke(serviceProviderEngineScope); } 二、ASP.NET Core中注册服务上边仔细研读了ASP.NET Core的源码,并且分析了依赖注入的实现原理。接下来就是说下在应用层面上应该如何使用。在startup类中,可以在ConfigureServices方法中注册服务: public void ConfigureServices(IServiceCollection services) 1、IServiceCollection中的方法和扩展方法下面可用于服务的注册,即服务注册的方法: AddScoped,添加服务,服务实例的生命周期为Scoped。 AddTransient,添加服务,服务实例的生命周期为Transient(每次被使用都创建新对象)。 AddSingleton,添加服务,服务实例的生命周期为单例。 AddMvc,添加所有MVC所需的服务。 AddMvcCore,仅添加核心必要的MVC所需的服务。 AddControllers,添加启用Controller 所需要的服务,不包括View和Pages所需要的服务。 AddControllersWithViews,添加启用 Controller 以及 Razor 页面所需要的服务。 AddRazorPages,添加 Razor Pages 所需要的服务。 AddAntiforgery,添加防止CSRF攻击的服务。 AddAuthentication,添加启用Authentication中间件所需的服务。 AddAuthenticationCore,添加启用Authentication中间件所需的核心服务。 AddAuthorization,添加启用Authorization中间件所需的服务。 AddAuthorizationCore,添加启用Authorization中间件所需的核心服务。 AddAuthorizationPolicyEvaluator,添加 Authorization 策略评估服务。 AddCertificateForwarding,添加CertificateForwarding中间件所需的服务。 AddConnections,添加 http://ASP.NET Core Connection Handlers 所需的服务。 AddCors,添加CORS中间件 所需的服务。 AddDataProtection,添加 http://ASP.NET Core Data Protection 所需的服务。 AddDirectoryBrowser,添加 DirectoryBrowser 中间件所需的服务。 AddDistributedMemoryCache,添加分布式缓冲服务IDistributedCache,默认的实现将缓冲保存在内存中,要实现实际上的分布式缓冲你需要提供一个保存缓存的实现(Redis或数据库,如AddStackExchangeRedisCache和AddDistributedSqlServerCache)。 AddHealthChecks,添加HealthChecks中间件所需的服务。 AddHostedService,添加宿主服务,如持续运行的服务。 AddHostFiltering,添加HostFiltering中间件所需的服务。 AddHsts,添加HSTS中间件所需的服务。 AddHttpClient,添加IHttpClientFactory服务用于获取在服务器端发起Http请求的HttpClient对象。 AddHttpContextAccessor,添加Http上下文访问器服务,在例如Controller里有HttpContext属性的地方优先使用HttpContext,但如果在一个自定义的服务里你就需要IHttpContextAccessor服务来获取Http上下文。 AddHttpsRedirection,为HttpsRedirection中间件添加所需的服务。 AddIdentity,添加默认的身份系统,并制定 Role和User类型。 AddIdentityCore,添加默认身份执行的核心部分,并制定User类型。 AddLocalization,添加本地化服务。 AddLogging,添加日志服务。 AddMemoryCache,添加非分布式的内存缓存服务。 AddOptions,添加 Option 服务。 AddResponseCaching,为ResponseCaching中间件添加所需的服务。 AddResponseCompression,为ResponseCompression中间件添加所需的服务。 AddRouting,添加Routing中间件所需的服务。 AddSignalR,添加SignalR所需的服务。 AddSignalRCore,添加SignalR所需的核心服务。 AddServerSideBlazor,添加 Server-Side Blazor所需的服务。 AddWebEncoders,添加 HtmlEncoder,JavaScriptEncoder,UrlEncoder 三个服务。 2、自定义的IServiceCollection扩展方法这里不在详述。 三、ASP.NET Core中注入服务1、构造函数注入(1)示例一:Serilog日志服务自定义一个IHostBuilder扩展方法UseSeriLog,并注册该服务,如下图:
在ValuesController中注入该服务: namespace CrmRedevelop.Controllers { [Route("api/[controller]")] [ApiController] public class ValuesController : ControllerBase { private readonly ILogger _logger; public ValuesController(ILogger logger) { _logger = logger; } // GET api/<ValuesController>/5 [HttpGet("{id}")] public string Get(int id) { _logger.Information("构造函数注入"); return "value"; } } } 看下效果: (2)示例二:IHostEnvironmentnamespace CrmRedevelop.Controllers { [Route("api/[controller]")] [ApiController] public class ValuesController1 : ControllerBase { private readonly IHostEnvironment _hostEnvironment; public ValuesController1(IHostEnvironment hostEnvironment) { _hostEnvironment = hostEnvironment; } // GET: api/<ValuesController> [HttpGet] public IEnumerable<string> Get() { var path = _hostEnvironment.ContentRootPath; return new string[] { path }; } } } 看下效果:
2、特性FromServices注入FromServicesAttribute 允许将服务直接注入到操作方法,而无需使用构造函数注入。 (1)示例一:Serilog日志服务namespace CrmRedevelop.Controllers { [Route("api/[controller]")] [ApiController] public class ValuesController : ControllerBase { // GET: api/<ValuesController> [HttpGet] public IEnumerable<string> Get([FromServices] ILogger logger) { logger.Information("利用特性FromServices注入服务"); return new string[] { "value1", "value2" }; |
请发表评论