[Asp.net 5] DependencyInjection project code analysis 4-Microsoft's implementation (3 ),

Source: Internet
Author: User

[Asp.net 5] DependencyInjection project code analysis 4-Microsoft's implementation (3 ),

Five articles have been written in this series. The link address is as follows:

[Asp.net 5] DependencyInjection project code analysis

[Asp.net 5] DependencyInjection project code analysis 2-Autofac

[Asp.net 5] DependencyInjection project code analysis 3-Ninject

[Asp.net 5] DependencyInjection project code analysis 4-Microsoft's implementation (1)

[Asp.net 5] DependencyInjection project code analysis 4-Microsoft's implementation (2)

 

If you want to have a better understanding of this article, we suggest you read it first.

"[Asp.net 5] DependencyInjection project code analysis"

"[Asp.net 5] DependencyInjection project code analysis 4-Microsoft's implementation (1 )"

"[Asp.net 5] DependencyInjection project code analysis 4-Microsoft's implementation (2 )".

In the previous "above" and ", the" two articles have already introducedServiceTable,IGenericService, IService, IServiceCallSite,ServiceEntry,GenericService,InstanceService,FactoryService,Service. This section describes the core "ServiceProvider" class.

IServiceProvider class

IServiceProviderClass is a direct external interface in Microsoft's DependencyInjection. ServiceProvider directly implementsIServiceProviderIt also provides core functions for external users.

ServiceProvider must be able to obtain injection classes and injection classes of different ranges according to different definitions. ServiceProvider uses different logic for different ranges (Transient, Scoped, and Singleton. Let's make a simple analysis.

  • For Transient, a new instance is created each time. Therefore, you only need to directly create the injection class instance in the Code and do not need to cache the class;
  • For Singleton, there is only one global instance. The code can cache the created object to a static dictionary table, each time this type of instance is required, the instance is first searched in the Global static dictionary table. If the instance exists, the instance is directly returned. If the instance does not exist, the instance is added to the dictionary table and then returned. (In fact, the source code is not cached in the global variable. The specific implementation method will be explained later.)
  • For Scoped, each Scope is unique and different Scope ranges are different. This is more difficult to implement. However, we can simply guess the code of an external call, and then check the source code for verification.

The following code is called for different Scoped ranges.

Public void ScopedServiceCanBeResolved () {IServiceProvider container = CreateContainer (); var scopeFactory = container. getService <IServiceScopeFactory> (); using (var scope = scopeFactory. createid () {var containerScopedService = container. getService <IFakeScopedService> (); var scopedService1 = scope. serviceProvider. getService <IFakeScopedService> (); var scopedService2 = scope. serviceProvider. getService <IFakeScopedService> (); Assert. notEqual (containerScopedService, scopedService1); Assert. equal (scopedService1, scopedService2) ;}} [Fact] public void NestedScopedServiceCanBeResolved () {IServiceProvider container = CreateContainer (); IServiceScopeFactory outerScopeFactory = container. getService <IServiceScopeFactory> (); using (var outerScope = outerScopeFactory. createid () {var innerScopeFactory = outerScope. serviceProvider. getService <IServiceScopeFactory> (); using (var innerScope = innerScopeFactory. createid () {var outerScopedService = outerScope. serviceProvider. getService <IFakeScopedService> (); var innerScopedService = innerScope. serviceProvider. getService <IFakeScopedService> (); Assert. notEqual (outerScopedService, innerScopedService );}}}Createid

We can inject instances based on different Scoped instances.Different IServiceScope objectsOfServiceProviderProperty, and then create it through this property. Because they are different IServiceScope objects, we can boldly assume thatServiceProviderAttributes are also different.ServiceProviderObject. So eachServiceProviderYou only need to maintain a copy of the injected object. Because the IServiceScope object implements the IDisposable interface (the objects used in using implement the IDisposable interface. When the using range ends, will automatically call the IDisposable Dispose method), but the injected object is cached inServiceProviderAttribute object, so let'sServiceProviderClass also implements the IDisposable interface, which is called within the iservicw.dispose MethodServiceProviderThe Dispose method of the class.

Through the above analysis, we can roughly imagineServiceProviderClass definition, the following isServiceProviderSource code for class reduction:

internal class ServiceProvider : IServiceProvider, IDisposable    {        private readonly object _sync = new object();        private readonly ServiceProvider _root;        private readonly ServiceTable _table;        private readonly Dictionary<IService, object> _resolvedServices = new Dictionary<IService, object>();        private ConcurrentBag<IDisposable> _disposables = new ConcurrentBag<IDisposable>();        public ServiceProvider(IEnumerable<ServiceDescriptor> serviceDescriptors)        {            _root = this;            _table = new ServiceTable(serviceDescriptors);            _table.Add(typeof(IServiceProvider), new ServiceProviderService());            _table.Add(typeof(IServiceScopeFactory), new ServiceScopeService());            _table.Add(typeof(IEnumerable<>), new OpenIEnumerableService(_table));        }        internal ServiceProvider(ServiceProvider parent)        {            _root = parent._root;            _table = parent._table;        }        public object GetService(Type serviceType);
public void Dispose() { var disposables = Interlocked.Exchange(ref _disposables, null); if (disposables != null) { foreach (var disposable in disposables) { disposable.Dispose(); } } }}

ForServiceProviderThe object has five attributes,

  • "_ Sync" is the Lock Object used for multi-thread synchronization. We can ignore it.
  • The "_ table" object of ServiceTable is a dictionary table for internal maintenance of injection class relationships.
  • ResolvedServices is used to maintain the injection objects that have been created in the specified range. When an object in the specified range exists, it first checks whether the dictionary table has an instance. If yes, it returns directly, no new instance is created and added to the dictionary table, and the newly created instance is returned.
  • "Disposables" is a list supported by multiple threads. It can be seen from the name that this is the object to be released after Dispose is called. You can also authenticate this point from the Dispose method. (When the injected object implements the IDisposable interface, you need to call its Dispose method to release the key resources it uses after use, so as to avoid Memory garbage and resource waste .)
  • The "root" attribute of ServiceProvider type. This... (I would probably ask what this is? Is ServiceProvider also a chain structure? But cannot it be called root? Is it the implementation of Singleton, but it is gross and not global, and each ServiceProvider has this copy ??). According to its simple comments to ghosts, and repeated experiments, it is indeed the implementation of Singleton.

Expand the Root attribute of ServiceProvider

First, we did not notice a problem, that isServiceProviderClass definition is not public, but internal. Let's recall the definition of the class:

internal class ServiceProvider : IServiceProvider, IDisposable

So we cannot call/build it out there.ServiceProviderOnly instances within the scope of the Assembly. Where can I call the constructor of this class?
The result shows that both constructors are called only once. The called code is listed below:

Public static class ServiceCollectionExtensions {public static IServiceProvider BuildServiceProvider (this IServiceCollection services) {return new ServiceProvider (services) ;}} internal class ServiceScopeFactory: IServiceScopeFactory {private readonly ServiceProvider _ provider; public ServiceScopeFactory (ServiceProvider provider) {_ provider = provider;} public iservicw.createid () {return new serviceid (new ServiceProvider (_ provider ));}}ServiceProvider Constructor
  • The constructor called by the ServiceCollectionExtensions class: This is an extension of the IServiceCollection interface (inherited from IList <ServiceDescriptor>). It is actually created using the IServiceCollection object.ServiceProviderObject for external calls. This is the entry to dependency injection implemented by Microsoft. We can see that the IServiceCollection ParameterServiceProviderConstructor, [_ rOot = this]. Description: The newly createdServiceProviderIs the so-called root.
  • ForServiceProviderTheServiceProviderConstructor. [Root = parent. _ root], IndicatingServiceProviderObject and InputServiceProviderThe _ root of the object actually points to the same address and is created using IServiceCollection.ServiceProviderObject [Note that IServiceCollection. BuildServiceProvider is only used once, although it is not defined as globally unique]. That is to say, created by using IServiceCollection. BuildServiceProviderServiceProviderThe scope is global.ServiceProviderDirectly created scpoed range objects will also become global objects (no time to call its IDisposable interface ).
public ServiceProvider(IEnumerable<ServiceDescriptor> serviceDescriptors)        {            _root = this;            _table = new ServiceTable(serviceDescriptors);            _table.Add(typeof(IServiceProvider), new ServiceProviderService());            _table.Add(typeof(IServiceScopeFactory), new ServiceScopeService());            _table.Add(typeof(IEnumerable<>), new OpenIEnumerableService(_table));        }        internal ServiceProvider(ServiceProvider parent)        {            _root = parent._root;            _table = parent._table;        }

ServiceProviderSo we can continue to look at other aspects of the constructor (the above Code is its constructor ). We found that IServiceProvider, IServiceScopeFactory, and IEnumerable are added to ServiceTable.

  • IServiceProvider injection indicates that a new IServiceProvider can be created. As mentioned above, only two places can be createdServiceProviderAnd does not contain the ServiceProviderService method. In fact, ServiceProviderService is the implementation class of the IService and IServiceCallSite interfaces introduced earlier. When the IServiceCallSite method "Invoke (ServiceProvider provider)" is called, the provider is directly returned, and no newServiceProvider(IServiceProvider) Object, but use the existing
  • IServiceScopeFactory injection and ServiceScopeService implement the IService and IServiceCallSite interfaces, and ServiceScopeFactory (IServiceScopeFactory) is created internally ).
  • The injection of IEnumerable <> is skipped due to limited space.
Internal class ServiceProviderService: IService, IServiceCallSite {public IService Next {get; set;} public ServiceLifetime Lifetime {get {return ServiceLifetime. scoped; }} public IServiceCallSite CreateCallSite (ServiceProvider provider, ISet <Type> callSiteChain) {return this;} public object Invoke (ServiceProvider provider) {return provider ;} public Expression Build (Expression provider) {return provider ;}}ServiceProviderService internal class ServiceScopeService: IService, IServiceCallSite {public IService Next {get; set;} public ServiceLifetime Lifetime {get {return ServiceLifetime. scoped ;}} public IServiceCallSite CreateCallSite (ServiceProvider provider, ISet <Type> callSiteChain) {return this;} public object Invoke (ServiceProvider provider) {return new ServiceScopeFactory (provider );} public Expression Build (Expression provider) {return Expression. new (typeof (ServiceScopeFactory ). getTypeInfo (). declaredConstructors. single (), provider) ;}} internal class ServiceScopeFactory: IServiceScopeFactory {private readonly ServiceProvider _ provider; public ServiceScopeFactory (ServiceProvider provider) {_ provider = provider;} public iservicw.creat.pdf () {return new serviceid (new ServiceProvider (_ provider) ;}} internal class serviceid: iserviceid {private readonly ServiceProvider _ scopedProvider; public serviceid (ServiceProvider scopedProvider) {_ scopedProvider = scopedProvider ;} public IServiceProvider ServiceProvider {get {return _ scopedProvider;} public void Dispose () {_ scopedProvider. dispose ();}}ServiceScopeService, ServiceScopeFactory, servic.pdf

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.