ASP.NET Core 支持依賴注入, 也推薦使用依賴注入. 主要作用是用來(lái)降低代碼之間的耦合度.
什么是控制反轉(zhuǎn)?控制反轉(zhuǎn)(Inversion of Control,縮寫(xiě)為IoC),是面向?qū)ο缶幊讨械囊环N設(shè)計(jì)原則,可以用來(lái)減低計(jì)算機(jī)代碼之間的耦合度。
其中最常見(jiàn)的方式叫做"依賴注入"(Dependency Injection,簡(jiǎn)稱DI),還有一種方式叫"依賴查找"(Dependency Lookup)
什么是依賴注入?這個(gè)概念分開(kāi)來(lái)理解
1. 依賴, 當(dāng)B類里要調(diào)用A類完成某個(gè)功能, 那么就可以說(shuō)是B依賴于A.
public class ClassA
{
public string FnA(string str)
{
return "A-" + str;
}
}
public class ClassB
{
ClassA ca = new ClassA();
public string FnB(string str)
{
var art = ca.FnA(str);
return "B-" + art;
}
}
上面這種方式是很常見(jiàn)的, 但是并不符合依賴的原則. 依賴的原則是: 依賴于抽象,而不是具體的實(shí)現(xiàn). 也就是B類不能直接依賴A類, 應(yīng)該依賴A的抽象接口.
2. 注入. 在這里C類不去實(shí)例化A類,而是通過(guò)其他人傳遞給我,我只用就好。簡(jiǎn)單來(lái)說(shuō)就是別人對(duì)依賴創(chuàng)建實(shí)例化,我自己只負(fù)責(zé)使用,這個(gè)過(guò)程可以理解為注入.
public class ClassC
{
ClassA _ca;
public ClassC(ClassA ca)
{
_ca = ca;
}
public string FnC(string str)
{
var art = _ca.FnA(str);
return "C-" + art;
}
}
在上面的依賴中講過(guò), 最好不要直接依賴實(shí)現(xiàn),應(yīng)該依賴抽象接口. 通過(guò)注入我們了解到, 我們不應(yīng)該直接實(shí)例化依賴項(xiàng),而應(yīng)該別人創(chuàng)建, 我們只負(fù)責(zé)使用. 綜合一下, 我們就將原來(lái)的使用方式改為以下方式
/// <summary>
/// 抽象接口A
/// </summary>
public interface InterfaceA
{
string FnA(string str);
}
/// <summary>
/// 抽象接口A的具體實(shí)現(xiàn)
/// </summary>
public class ClassA:InterfaceA
{
public string FnA(string str)
{
return "A-" + str;
}
}
/// <summary>
/// 傳統(tǒng)方式
/// </summary>
public class ClassB
{
ClassA ca = new ClassA();
public string FnB(string str)
{
var art = ca.FnA(str);
return "B-" + art;
}
}
/// <summary>
/// 依賴注入方式, 1.依賴于抽象接口,而不是具體實(shí)現(xiàn); 2.依賴項(xiàng)不由我們自己創(chuàng)建,而只是負(fù)責(zé)使用
/// </summary>
public class ClassD
{
readonly InterfaceA _ica;
public ClassD(InterfaceA ica)
{
_ica = ica;
}
public string FnD(string str)
{
var art = _ica.FnA(str);
return "D-" + art;
}
}
ClassB就是我們常見(jiàn)的使用方式, ClassD就是我們使用依賴注入的使用方式.
如何在.net core 里使用依賴注入?1. 創(chuàng)建抽象接口(過(guò)程略)
2. 實(shí)現(xiàn)抽象接口(過(guò)程略)
3. 在Startup類的ConfigureServices方法中注冊(cè)服務(wù)
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddTransient<InterfaceA, ClassA>();
}
4. 在Controller中使用, 通過(guò)在構(gòu)造函數(shù)中獲取實(shí)例, 然后使用
[ApiController]
[Route("[controller]/[action]")]
public class DemoController : ControllerBase
{
private readonly InterfaceA _interfaceA;
/// <summary>
/// 通過(guò)構(gòu)造函數(shù)獲取實(shí)例
/// </summary>
/// <param name="interfaceA"></param>
public DemoController(InterfaceA interfaceA)
{
_interfaceA = interfaceA;
}
public IActionResult TestGet()
{
var rt = _interfaceA.FnA("uuu");
return Ok(rt);
}
}
結(jié)果
以上就是一個(gè)簡(jiǎn)單的.net core 使用依賴注入的例子
如何選擇服務(wù)的生命周期?在上面的第三步, 在注冊(cè)服務(wù)的時(shí)候我們使用的AddTransient , 除此之外還有 AddScoped,AddSingleton
AddTransient 暫時(shí)暫時(shí)生存期服務(wù) (AddTransient) 是每次從服務(wù)容器進(jìn)行請(qǐng)求時(shí)創(chuàng)建的。 這種生存期適合輕量級(jí)、 無(wú)狀態(tài)的服務(wù)。
AddScoped 范圍內(nèi)作用域生存期服務(wù) (AddScoped) 以每個(gè)客戶端請(qǐng)求(連接)一次的方式創(chuàng)建。注意:在中間件內(nèi)使用有作用域的服務(wù)時(shí),請(qǐng)將該服務(wù)注入至 Invoke 或 InvokeAsync 方法。 請(qǐng)不要通過(guò)構(gòu)造函數(shù)注入進(jìn)行注入,因?yàn)樗鼤?huì)強(qiáng)制服務(wù)的行為與單一實(shí)例類似。 有關(guān)詳細(xì)信息,請(qǐng)參閱 寫(xiě)入自定義 ASP.NET Core 中間件。
AddSingleton 單例單一實(shí)例生存期服務(wù) (AddSingleton) 是在第一次請(qǐng)求時(shí)(或者在運(yùn)行 Startup.ConfigureServices 并且使用服務(wù)注冊(cè)指定實(shí)例時(shí))創(chuàng)建的。 每個(gè)后續(xù)請(qǐng)求都使用相同的實(shí)例。 如果應(yīng)用需要單一實(shí)例行為,建議允許服務(wù)容器管理服務(wù)的生存期。 不要實(shí)現(xiàn)單一實(shí)例設(shè)計(jì)模式并提供用戶代碼來(lái)管理對(duì)象在類中的生存期。注意:從單一實(shí)例解析有作用域的服務(wù)很危險(xiǎn)。 當(dāng)處理后續(xù)請(qǐng)求時(shí),它可能會(huì)導(dǎo)致服務(wù)處于不正確的狀態(tài)。
什么是容器?講到這里可能大家會(huì)有個(gè)疑問(wèn).
依賴注入把依賴的創(chuàng)建交給了別人, 我們只負(fù)責(zé)使用, 那么這個(gè)誰(shuí)創(chuàng)建, 在哪兒創(chuàng)建, 怎么管理?
這個(gè)就引發(fā)了一個(gè)新的概念--容器. 容器就是負(fù)責(zé)關(guān)系的系統(tǒng)所有的依賴. 在我們.net core 有一個(gè)默認(rèn)的容器, 專門(mén)用于管理這些依賴.
但是默認(rèn)的容器在小型項(xiàng)目的時(shí)候夠了,但是大型項(xiàng)目就不夠了.
我們通過(guò)AddTransient這些方式去注冊(cè)服務(wù), 那么一個(gè)項(xiàng)目有非常的這種服務(wù), 每一個(gè)都注冊(cè),在startup這個(gè)里面就變非常臃腫負(fù)責(zé). 這個(gè)時(shí)候我們需要替換原來(lái)的容器.
如何更換默認(rèn)容器?在這里我們介紹一種常用的第三方容器: AutoFac, .net core 版本使用的是3.1 其他版本會(huì)略有不同.
一. nuget安裝 Autofac.Extensions.DependencyInjection二. 修改 Program.cs 文件
添加一句
.UseServiceProviderFactory(new Autofac.Extensions.DependencyInjection.AutofacServiceProviderFactory())//Autofac
三. 修改 Startup.cs
新增ConfigureContainer方法
public void ConfigureContainer(ContainerBuilder builder)
{
// 方式一 默認(rèn)注冊(cè)
builder.RegisterType<ClassA>().As<InterfaceA>();//注冊(cè) 類似默認(rèn)容器的services.AddTransient<InterfaceA, ClassA>();
}
上面這種方式是默認(rèn)的注冊(cè), 類似.net core 自帶的注冊(cè). 但是并不合適我們批量注冊(cè), 下面介紹一種掃描程序集的注冊(cè)方式
public void ConfigureContainer(ContainerBuilder builder)
{
//方式二 掃描程序集, RegisterAssemblyTypes接收包含一個(gè)或多個(gè)程序集的數(shù)組作為參數(shù). 默認(rèn)地, 程序中所有具體的類都將被注冊(cè).
var asm = Assembly.Load("Service");//指定dll名稱的程序集集
var defulatAsm = Assembly.GetExecutingAssembly();//默認(rèn)執(zhí)行的dll
builder.RegisterAssemblyTypes(asm, defulatAsm)
.PublicOnly()//僅注冊(cè)public的方法
.Except<Service.DemoService>()//排除某個(gè)類
.Where(t => t.Name.EndsWith("Service") || t.Name == "ClassA")//可以在這里寫(xiě)一些過(guò)濾類名規(guī)則
.AsImplementedInterfaces();
}
在controller里使用的方式和以前一樣
參考文獻(xiàn)
.net core 依賴注入
Autofac 入門(mén)
最后多說(shuō)一句,很多人學(xué)Python過(guò)程中會(huì)遇到各種煩惱問(wèn)題,沒(méi)有人解答容易放棄。小編是一名python開(kāi)發(fā)工程師,這里有我自己整理了一套最新的python系統(tǒng)學(xué)習(xí)教程,包括從基礎(chǔ)的python腳本到web開(kāi)發(fā)、爬蟲(chóng)、數(shù)據(jù)分析、數(shù)據(jù)可視化、機(jī)器學(xué)習(xí)等。想要這些資料的可以關(guān)注小編,并在后臺(tái)私信小編:“01”即可領(lǐng)取。