ASP.Net Core-依賴注入IoC

1、Ioc數據庫

IoC全稱Inverse of Control,控制反轉。設計模式

類庫和框架的不一樣之處在於,類庫是實現某種單一功能的API,框架是針對一個任務把這些單一功能串聯起來造成一個完整的流程,這個流程在一個引擎驅動下被執行。緩存

IoC的整體設計是要把在應用程序的流程控制轉移到框架中,實現對流程的複用,這 符合軟件設計的基本原則-重用性。app

IoC不是一種設計模式,它是一種設計原則。而且不少設計模式都遵循了這種原則。好比:模板模式、工廠模式、抽象工廠模式。框架

 

2、DIide

DI全稱Dependency Indection,依賴注入。它是IoC模式的一種。函數

咱們寫的對象要完成某個功能可能要依賴於另一個對象,好比咱們要添加一我的員,每每會在邏輯層調用數據操做層來實現添加到數據庫的操做。DI會在程序初始化的時候,把數據操做層的接口和實現接口的類關聯起來,那麼在邏輯層咱們只要聲明要調用的具體數據操做層的接口,調用接口的方法,這樣就實現了邏輯層和數據操做層的解耦。ui

所謂依賴注入能夠理解爲一種針對依賴的字段或者屬性的一種自動初始化方式。this

 

舉例說明,當咱們經過VS2015建立了一個.Net Core項目,而且帶有我的身份驗證Identity,具體如何建立在此再也不細說。spa

咱們看到在Startup中,有個方法

       

// This method gets called by the runtime. Use this method to add services to the container.

        public void ConfigureServices(IServiceCollection services)

        {

            // Add framework services.

            services.AddDbContext<ApplicationDbContext>(options =>

                options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

            services.AddIdentity<ApplicationUser, IdentityRole>()

                .AddEntityFrameworkStores<ApplicationDbContext>()

                .AddDefaultTokenProviders();

            services.AddMvc();

            // Add application services.

            services.AddTransient<IEmailSender, AuthMessageSender>();

            services.AddTransient<ISmsSender, AuthMessageSender>();

        }
View Code

 

Controller中:

[Authorize]
public class AccountController : Controller
{
     private readonly UserManager<ApplicationUser> _userManager;
     private readonly SignInManager<ApplicationUser> _signInManager;
     private readonly IEmailSender _emailSender;
     private readonly ISmsSender _smsSender;
     private readonly ILogger _logger;

     public AccountController(
         UserManager<ApplicationUser> userManager,
         SignInManager<ApplicationUser> signInManager,
         IEmailSender emailSender,
         ISmsSender smsSender,
         ILoggerFactory loggerFactory)
     {
         _userManager = userManager;
         _signInManager = signInManager;
         _emailSender = emailSender;
         _smsSender = smsSender;
         _logger = loggerFactory.CreateLogger<AccountController>();
     }
}
View Code

 

咱們看到,咱們並無實例化AccountController中的字段,只是在構造函數把相關聯的字段當作參數傳進來,系統自動就會實例化。這個實例化的過程就是DI幫助咱們完成的。

DI注入方式有3種:構造器注入、屬性注入、方法注入。

DI容器就是一個服務的提供者。當須要某個服務的時候,只要從DI容器中獲取就能夠。

 

3、.NET 中的DI

ServiceProvider對象是DI容器的核心對象,他在Microsoft.Extensions.DependencyInjection.dll程序集的同名命名空間下。是一個程序集內部類。這個類的主要任務就是根據服務類型提供服務對象。

與這個類相關聯的類有:ServiceCallSite、Service、ServiceEntry和ServiceTable。他們都有相應的接口。

 

1.ServiceCallSite

服務的最終提供者就是這個對象,這個對象繼承自接口IServiceCallSite。

namespace Microsoft.Extensions.DependencyInjection.ServiceLookup
{
    using Microsoft.Extensions.DependencyInjection;
    using System;
    using System.Linq.Expressions;

    internal interface IServiceCallSite
    {
        Expression Build(Expression provider);
        object Invoke(ServiceProvider provider);
    }
}
View Code

當須要一個服務實例的時候,會去對應的ServiceCallSite中調用Invoke方法,返回須要的實例。同時,還會調用Invoke方法返回表達式,並會緩存起來,等到下次獲取相同實例的時候直接獲取。

2.Service

當咱們獲取服務對象實例的時候是根據ServiceCollection提供的。ServiceCollection和咱們鏈接很是緊密,就是咱們在Startup中添加的服務於實現的關聯。

ServiceCollection中保存的就是ServiceDescriptor,每一個ServiceDescriptor都會被轉化成Service,繼承自接口IService。

namespace Microsoft.Extensions.DependencyInjection.ServiceLookup
{
    using Microsoft.Extensions.DependencyInjection;
    using System;
    using System.Collections.Generic;

    internal interface IService
    {
        IServiceCallSite CreateCallSite(ServiceProvider provider, ISet<Type> callSiteChain);

        ServiceLifetime Lifetime { get; }

        IService Next { get; set; }
    }
}
View Code

咱們看到,這個接口中有CreateCallSite獲得一個ServiceCallSite實例。每一個Service都是以鏈表的形式存在,Next表示鏈表的下一個節點,這個鏈表就是具備相同的服務類型組成。

3.ServiceEntry

表示上面說的鏈表。

namespace Microsoft.Extensions.DependencyInjection.ServiceLookup
{
    using System;
    using System.Runtime.CompilerServices;

    internal class ServiceEntry
    {
        private object _sync = new object();

        public ServiceEntry(IService service)
        {
            this.First = service;
            this.Last = service;
        }

        public void Add(IService service)
        {
            object obj2 = this._sync;
            lock (obj2)
            {
                this.Last.Next = service;
                this.Last = service;
            }
        }

        public IService First { get; private set; }

        public IService Last { get; private set; }
    }
} 
View Code

4.ServiceTable

多個ServiceEntry組成一個ServiceTable。

namespace Microsoft.Extensions.DependencyInjection.ServiceLookup
{
    using Microsoft.Extensions.DependencyInjection;
    using System;
    using System.Collections.Concurrent;
    using System.Collections.Generic;
    using System.Reflection;
    using System.Runtime.InteropServices;

    internal class ServiceTable
    {
        private readonly Dictionary<Type, List<IGenericService>> _genericServices = new Dictionary<Type, List<IGenericService>>();
        private readonly ConcurrentDictionary<Type, Func<ServiceProvider, object>> _realizedServices = new ConcurrentDictionary<Type, Func<ServiceProvider, object>>();
        private readonly Dictionary<Type, ServiceEntry> _services = new Dictionary<Type, ServiceEntry>();
        private readonly object _sync = new object();

        public ServiceTable(IEnumerable<ServiceDescriptor> descriptors)
        {
            foreach (ServiceDescriptor descriptor in descriptors)
            {
                if (IntrospectionExtensions.GetTypeInfo(descriptor.ServiceType).IsGenericTypeDefinition)
                {
                    TypeInfo info = (descriptor.ImplementationType == null) ? null : IntrospectionExtensions.GetTypeInfo(descriptor.ImplementationType);
                    if ((info == null) || !info.IsGenericTypeDefinition)
                    {
                        throw new ArgumentException(Resources.FormatOpenGenericServiceRequiresOpenGenericImplementation(descriptor.ServiceType), "descriptors");
                    }
                    if (info.IsAbstract || info.IsInterface)
                    {
                        throw new ArgumentException(Resources.FormatTypeCannotBeActivated(descriptor.ImplementationType, descriptor.ServiceType));
                    }
                    this.Add(descriptor.ServiceType, new GenericService(descriptor));
                }
                else if (descriptor.ImplementationInstance != null)
                {
                    this.Add(descriptor.ServiceType, new InstanceService(descriptor));
                }
                else if (descriptor.ImplementationFactory != null)
                {
                    this.Add(descriptor.ServiceType, new FactoryService(descriptor));
                }
                else
                {
                    TypeInfo typeInfo = IntrospectionExtensions.GetTypeInfo(descriptor.ImplementationType);
                    if ((typeInfo.IsGenericTypeDefinition || typeInfo.IsAbstract) || typeInfo.IsInterface)
                    {
                        throw new ArgumentException(Resources.FormatTypeCannotBeActivated(descriptor.ImplementationType, descriptor.ServiceType));
                    }
                    this.Add(descriptor.ServiceType, new Service(descriptor));
                }
            }
        }

        public void Add(Type serviceType, IGenericService genericService)
        {
            object obj2 = this._sync;
            lock (obj2)
            {
                List<IGenericService> list;
                if (!this._genericServices.TryGetValue(serviceType, ref list))
                {
                    list = new List<IGenericService>();
                    this._genericServices.set_Item(serviceType, list);
                }
                list.Add(genericService);
            }
        }

        public void Add(Type serviceType, IService service)
        {
            object obj2 = this._sync;
            lock (obj2)
            {
                ServiceEntry entry;
                if (this._services.TryGetValue(serviceType, ref entry))
                {
                    entry.Add(service);
                }
                else
                {
                    this._services.set_Item(serviceType, new ServiceEntry(service));
                }
            }
        }

        public bool TryGetEntry(Type serviceType, out ServiceEntry entry)
        {
            object obj2 = this._sync;
            lock (obj2)
            {
                if (this._services.TryGetValue(serviceType, ref entry))
                {
                    return true;
                }
                if (IntrospectionExtensions.GetTypeInfo(serviceType).IsGenericType)
                {
                    List<IGenericService> list;
                    Type genericTypeDefinition = serviceType.GetGenericTypeDefinition();
                    if (this._genericServices.TryGetValue(genericTypeDefinition, ref list))
                    {
                        using (List<IGenericService>.Enumerator enumerator = list.GetEnumerator())
                        {
                            while (enumerator.MoveNext())
                            {
                                IService service = enumerator.get_Current().GetService(serviceType);
                                if (service != null)
                                {
                                    this.Add(serviceType, service);
                                }
                            }
                        }
                        return this._services.TryGetValue(serviceType, ref entry);
                    }
                }
            }
            return false;
        }

        public ConcurrentDictionary<Type, Func<ServiceProvider, object>> RealizedServices
        {
            get
            {
                return this._realizedServices;
            }
        }
    }
} 
View Code

主要的方法就是在ServiceTable構造函數中,根據傳過來的ServiceDescriptor列表,其實就是咱們在Startup中註冊的服務與具體實現轉換過來的。

在這個構造函數中會先根據ServiceType轉換成ServiceEntry列表,再添加到Dictionary<Type, ServiceEntry> _services 中,也就是最終獲得的是_services類型。

5.ServiceProvider

   1internal class ServiceProvider : IServiceProvider, IDisposable

   2: {

   3:     public ServiceProvider Root { get; private set; }

   4:     public ServiceTable ServiceTable { get; private set; }

   5:     public ConcurrentDictionary<Type, Func<ServiceProvider, object>> RealizedServices { get; private set; } = new ConcurrentDictionary<Type, Func<ServiceProvider, object>>();

   6:     public IList<IDisposable> TransientDisposableServices { get; private set; } = new List<IDisposable>();

   7:     public ConcurrentDictionary<IService, object> ResolvedServices { get; private set; } = new ConcurrentDictionary<IService, object>();

   8:     

   9:     public ServiceProvider(IServiceCollection services)

  10:     {

  11:         this.Root         = this;

  12:         this.ServiceTable     = new ServiceTable(services);

  13:     }

  14:  

  15:     public object GetService(Type serviceType)

  16:     {

  17:         Func<ServiceProvider, object> serviceAccessor;

  18:         if (this.RealizedServices.TryGetValue(serviceType, out serviceAccessor))

  19:         {

  20:             return serviceAccessor(this);

  21:         }

  22:  

  23:         IServiceCallSite serviceCallSite = this.GetServiceCallSite(serviceType, new HashSet<Type>());

  24:         if (null != serviceCallSite)

  25:         {

  26:             var providerExpression = Expression.Parameter(typeof(ServiceProvider), "provider");

  27:             this.RealizedServices[serviceType] = Expression.Lambda<Func<ServiceProvider, object>>(serviceCallSite.Build(providerExpression), providerExpression).Compile();

  28:             return serviceCallSite.Invoke(this);

  29:         }

  30:  

  31:         this.RealizedServices[serviceType] = _ => null;

  32:         return null;

  33:     }

  34:  

  35:     public IServiceCallSite GetServiceCallSite(Type serviceType, ISet<Type> callSiteChain)

  36:     {

  37:             try

  38:             {

  39:                 if (callSiteChain.Contains(serviceType))

  40:                 {

  41:                     throw new InvalidOperationException(string.Format("A circular dependency was detected for the service of type '{0}'", serviceType.FullName);

  42:                 }

  43:                 callSiteChain.Add(serviceType);

  44:  

  45:                 ServiceEntry serviceEntry;

  46:                 if (this.ServiceTable.ServieEntries.TryGetValue(serviceType, 

  47:                     out serviceEntry))

  48:                 {

  49:                     return serviceEntry.Last.CreateCallSite(this, callSiteChain);

  50:                 }

  51:  

  52:                 //省略其餘代碼

  53:  

  54:                 return null;

  55:             }

  56:             finally

  57:             {

  58:                 callSiteChain.Remove(serviceType);

  59:             }

  60:     }    

  61:  

  62:     public void Dispose()

  63:     {

  64:         Array.ForEach(this.TransientDisposableServices.ToArray(), _ => _.Dispose());

  65:         Array.ForEach(this.ResolvedServices.Values.ToArray(), _ => (_ as IDisposable)?.Dispose());

  66:         this.TransientDisposableServices.Clear();

  67:         this.ResolvedServices.Clear();

  68:     }

  69:     //其餘成員

  70: }
View Code


以上藉助他人的代碼片斷,ServiceProvider中主要有幾個屬性,root指向本身;RealizedServices 就是在咱們講解ServiceCallSite時說道,最後獲得的Service會被生成委託以便下次調用,這個委託就存在這個屬性中。

這個類最主要的方法就是GetService,主要邏輯就是從RealizedServices 獲取當前服務的實例,若是有,直接返回,若是沒有,會從ServiceTable中找到對應的ServiceEntry,若是沒有返回null,若是有,調用ServiceEntry所在列表最後一個Service的CreateServiceCallSite方法建立一個ServiceCallSite對象(這一點說明了若是針對同一個服務類型註冊了多個ServiceDescriptor,在提供單個服務的時候老是使用最後一個 ServiceDescriptor)。

 

綜上,.net core中的DI容器的主要對象就是ServiceProvider、ServiceCallSite、Service、ServiceEntry和ServiceTable。主要的流程控制都放在ServiceProvider類中,這個類有一個ServiceTable(就是ServiceType和ServiceEntry的對應列表)。ServiceEntry就是一個鏈表,連接了當前ServiceType的全部的實例(不過獲得的實例老是以最後一個爲準),實例的類型都是Service類型。Service主要就是獲取ServiceCallSite對象,這個對象就是封裝了全部的獲取具體服務實例的邏輯,主要經過Invoke獲得實例,再調用Build生成表達式委託,存在ServiceProvider中。

ServiceProvider主要有一個方法GetService獲取服務實例。主要邏輯就是從RealizedServices 獲取當前服務的實例,若是有,直接返回,若是沒有,會從ServiceTable中找到對應的ServiceEntry,若是沒有返回null,若是有,調用ServiceEntry所在列表最後一個Service的CreateServiceCallSite方法建立一個ServiceCallSite對象(這一點說明了若是針對同一個服務類型註冊了多個ServiceDescriptor,在提供單個服務的時候老是使用最後一個 ServiceDescriptor)。

 

事後思考:

1. ServiceCallSite:獲取咱們要的最終的服務實例並緩存起來以備下次調用。

2.Service:獲取ServiceCallSite,由咱們註冊的服務轉換而來,鏈表形式存在,整個鏈表表示相同實例類型的實例。

3.ServiceEntry:對鏈表Service的封裝,有First、Last表示鏈表的第一個和最後一個,還有個Add方法。

4.ServiceTable:主要對象就是Dictionary<Type,ServiceEntry> _service,表示服務類型和服務實例鏈表的對應關係。

5.ServiceProvider:整個DI功能的控制者,主要方法就是GetService,根據類型獲取實例。

相關文章
相關標籤/搜索