1. 程式人生 > >.NET Core API框架實戰(五) 依賴注入 服務的註冊與提供

.NET Core API框架實戰(五) 依賴注入 服務的註冊與提供

ASP.NET Core 的底層設計支援和使用依賴注入。ASP.NET Core 
應用程式可以利用內建的框架服務將它們注入到啟動類Startup的方法中,並且應用程式服務ConfigureServices能夠配置注入。

依賴注入(Dependency injection,DI)是一種實現物件及其合作者或依賴項之間鬆散耦合的技術。

1、什麼是依賴?

當一個類需要另一個類協作來完成工作的時候就產生了依賴。比如我們在AccountController這個控制器需要完成和使用者相關的註冊、登入 等事情。其中的登入我們由EF結合Idnetity來完成,所以我們封裝了一個EFLoginService。這裡AccountController就有一個ILoginService的依賴。

這裡有一個設計原則:依賴於抽象,而不是具體的實現。所以我們給EFLoginService定義了一個介面,抽象了LoginService的行為。

 2、什麼是注入?

注入體現的是一個IOC(控制反轉的的思想),把依賴的建立丟給其它人,自己只負責使用,其它人丟給你依賴的這個過程理解為注入。

        private readonly IAccountAppService _accountAppService;
        /// <summary>
        /// 構造
        /// </summary>
        /// <param name="accountAppService">賬戶中心介面</param>
        public AccountController(
            IAccountAppService accountAppService
            )
        {
            _accountAppService = accountAppService;
        }

3、為什麼要反轉?


為了在業務變化的時候盡少改動程式碼可能造成的問題。
比如我們現在要把從EF中去驗證登入改為從Redis去讀,於是我們加了一個 RedisLoginService。這個時候我們只需要在原來注入的地方改一下就可以了。

// 用Redis來替換原來的EF登入 var controller = new AccountController(new RedisLoginService()); controller.Login(userName, password);

4、何為容器

上面我們在使用AccountController的時候,我們自己通過程式碼建立了一個IAccountServce的例項。想象一下,一個系統中如果有100個這樣的地方,我們是不是要在100個地方做這樣的事情? 控制是反轉了,依賴的建立也移交到了外部。現在的問題是依賴太多,我們需要一個地方統一管理系統中所有的依賴,容器誕生了。
 
容器負責兩件事情:

  1. 繫結服務與例項之間的關係
  2. 獲取例項,並對例項進行管理(建立與銷燬)

 

5、IOC容器的更換

1、首先得下載相應的NuGet包

Install-Package Autofac -Version 4.8.1

Install-Package Autofac.Extensions.DependencyInjection -Version 4.3.0

2、在ConfigureServices中建立容器物件,並返回IServiceProvider

 #region 依賴注入
            var builder = new ContainerBuilder();//例項化容器
            //註冊所有模組module
            builder.RegisterAssemblyModules(Assembly.GetExecutingAssembly());
            //獲取所有的程式集
            //var assemblys = BuildManager.GetReferencedAssemblies().Cast<Assembly>().ToArray();
            var assemblys = RuntimeHelper.GetAllAssemblies().ToArray();

            //註冊所有繼承IDependency介面的類
            //builder.RegisterAssemblyTypes().Where(type => typeof(IDependency).IsAssignableFrom(type) && !type.IsAbstract);
            //註冊倉儲,所有IRepository介面到Repository的對映
            builder.RegisterAssemblyTypes(assemblys).Where(t => t.Name.EndsWith("Repository") && !t.Name.StartsWith("I")).AsImplementedInterfaces();
            //註冊服務,所有IApplicationService到ApplicationService的對映
            builder.RegisterAssemblyTypes(assemblys).Where(t => t.Name.EndsWith("AppService") && !t.Name.StartsWith("I")).AsImplementedInterfaces();
            builder.Populate(services);
            this.ApplicationContainer = builder.Build();

            return new AutofacServiceProvider(this.ApplicationContainer); //第三方IOC接管 core內建DI容器 
            //return services.BuilderInterceptableServiceProvider(builder => builder.SetDynamicProxyFactory());
            #endregion

建立Runtime幫助獲取專案程式集,排除所有的系統程式集(Microsoft.***、System.***等)、Nuget下載包

using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;

namespace Dianshi.P2P.Core.Client.WebApi.Auth
{
    [ApiExplorerSettings(IgnoreApi = true)]
    public class RuntimeHelper
    {
        /// <summary>
        /// 獲取專案程式集,排除所有的系統程式集(Microsoft.***、System.***等)、Nuget下載包
        /// </summary>
        /// <returns></returns>
        public static IList<Assembly> GetAllAssemblies()
        {
            List<Assembly> list = new List<Assembly>();
            var deps = DependencyContext.Default;
            //排除所有的系統程式集、Nuget下載包
            var libs = deps.CompileLibraries.Where(lib => !lib.Serviceable && lib.Type != "package");
            foreach (var lib in libs)
            {
                try
                {
                    var assembly = AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(lib.Name));
                    list.Add(assembly);
                }
                catch (Exception ex)
                {
                    //
                }
            }
            return list;
        }

        public static Assembly GetAssembly(string assemblyName)
        {
            return GetAllAssemblies().FirstOrDefault(f => f.FullName.Contains(assemblyName));
        }

        public static IList<Type> GetAllTypes()
        {
            List<Type> list = new List<Type>();
            foreach (var assembly in GetAllAssemblies())
            {
                var typeinfos = assembly.DefinedTypes;
                foreach (var typeinfo in typeinfos)
                {
                    list.Add(typeinfo.AsType());
                }
            }
            return list;
        }

        /// <summary>
        /// 根據AssemblyName獲取所有的類
        /// </summary>
        /// <param name="assemblyName"></param>
        /// <returns></returns>
        public static IList<Type> GetTypesByAssembly(string assemblyName)
        {
            List<Type> list = new List<Type>();
            var assembly = AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(assemblyName));
            var typeinfos = assembly.DefinedTypes;
            foreach (var typeinfo in typeinfos)
            {
                list.Add(typeinfo.AsType());
            }
            return list;
        }

        public static Type GetImplementType(string typeName, Type baseInterfaceType)
        {
            return GetAllTypes().FirstOrDefault(t =>
            {
                if (t.Name == typeName && t.GetTypeInfo().GetInterfaces().Any(b => b.Name == baseInterfaceType.Name))
                {
                    var typeinfo = t.GetTypeInfo();
                    return typeinfo.IsClass && !typeinfo.IsAbstract && !typeinfo.IsGenericType;
                }
                return false;
            });
        }
    }
}

ConfigureServices的返回值(預設為void)為IServiceProvider

執行

 public ActionResult<string> Ioc()
        {
            return _accountAppService.Login(new Application.Members.Accounts.Dto.LoginInput() { Password = "1", Phone = "2" });
        }

完成注入,歡迎評論,歡迎指正!