.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個地方做這樣的事情? 控制是反轉了,依賴的建立也移交到了外部。現在的問題是依賴太多,我們需要一個地方統一管理系統中所有的依賴,容器誕生了。
容器負責兩件事情:
- 繫結服務與例項之間的關係
- 獲取例項,並對例項進行管理(建立與銷燬)
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" });
}
完成注入,歡迎評論,歡迎指正!