service 层注入不同的数据源_.NET 理论基础+实战控制台程序实现AutoFac注入
(給DotNet加星標(biāo),提升.Net技能)
轉(zhuǎn)自:在7樓?
cnblogs.com/RayWang/p/11128554.html
簡(jiǎn)介
該系列共5篇文章,旨在以實(shí)戰(zhàn)模式,在.NET下的
控制臺(tái)程序
Framework Mvc程序
Framework WebApi程序
Core Api程序
分別實(shí)現(xiàn)依賴(lài)注入。
其中.NET? Framework框架主要以如何引入AutoFac作為容器以及如何運(yùn)用AuotoFac為主,.NET Core框架除了研究引入AutoFac的兩種方式,同時(shí)也運(yùn)用反射技巧對(duì)其自帶的DI框架進(jìn)行了初步封裝,實(shí)現(xiàn)了相同的依賴(lài)注入效果。
項(xiàng)目架構(gòu)如下圖:
GitHub源碼地址:https://github.com/WangRui321/Ray.EssayNotes.AutoFac
適用對(duì)象
該項(xiàng)目主要實(shí)戰(zhàn)為主,理論部分我會(huì)結(jié)合例子和代碼,深入淺出地闡述,如果你是:
從來(lái)沒(méi)聽(tīng)過(guò)IoC、DI這些勞什子
了解一些依賴(lài)注入的理論知識(shí)但是缺乏實(shí)戰(zhàn)
在.Net Framework下已熟練運(yùn)用依賴(lài)注入,但在.NET Core還比較陌生
只要你花上半個(gè)小時(shí)認(rèn)真讀完每一句話(huà),我有信心這篇文章一定會(huì)對(duì)你有所幫助。
如果你是:
發(fā)量比我還少的秒天秒地的大牛
那么也歡迎閱讀,雖然可能對(duì)你幫助并不大,但是歡迎提供寶貴的意見(jiàn),有寫(xiě)的不好的地方可以互相交流~
理論基礎(chǔ)
依賴(lài)
依賴(lài),簡(jiǎn)單說(shuō)就是,當(dāng)一個(gè)類(lèi)需要另一個(gè)類(lèi)協(xié)作來(lái)完成工作的時(shí)候就產(chǎn)生了依賴(lài)。這也是耦合的一種形式。
舉個(gè)例子,比如標(biāo)準(zhǔn)的三層架構(gòu)模式
數(shù)據(jù)訪(fǎng)問(wèn)層(DAL)代碼:
////// 學(xué)生倉(cāng)儲(chǔ)
///
public class StudentRepository
{
public string GetName(long id){
return "學(xué)生張三";//造個(gè)假數(shù)據(jù)返回
}
}
業(yè)務(wù)層(BLL)代碼:
////// 學(xué)生邏輯處理
///
public class StudentService
{
private readonly StudentRepository _studentRepository;
public StudentService(){
_studentRepository = new StudentRepository();
}
public string GetStuName(long id){
var stu = _studentRepository.Get(id);
return stu.Name;
}
}
其中,StudentService的實(shí)現(xiàn),就必須要依賴(lài)于StudentRepository。而且這是一種緊耦合,一旦StudentRepository有任何更改,必然導(dǎo)致StudentService的代碼同樣也需要更改,這種情況是程序員們不愿意看到的。
接口驅(qū)動(dòng)
接口驅(qū)動(dòng)是為了實(shí)現(xiàn)一個(gè)設(shè)計(jì)原則:要依賴(lài)于抽象,而不是具體的實(shí)現(xiàn)。
還拿上面的例子說(shuō)明,現(xiàn)在我添加一個(gè)DAL的接口層,IStudentRepository,抽象出所需方法:
////// 學(xué)生倉(cāng)儲(chǔ)interface
///
public interface IStudentRepository
{
string GetName(long id);
}
然后讓StudentRepository去實(shí)現(xiàn)這個(gè)接口:
////// 學(xué)生倉(cāng)儲(chǔ)
///
public class StudentRepository : IStudentRepository
{
public string GetName(long id){
return "學(xué)生張三";//造個(gè)假數(shù)據(jù)返回
}
}
然后在StudentService里只依賴(lài)于IStudentRepository,以后的增刪改查都通過(guò)IStudentRepository這個(gè)抽象來(lái)做:
////// 學(xué)生邏輯處理
///
public class StudentService
{
private readonly IStudentRepository _studentRepository;
public StudentService(){
_studentRepository = new StudentRepository();
}
public string GetStuName(long id){
var stu = _studentRepository.Get(id);
return stu.Name;
}
}
這樣做的好處有兩個(gè),一個(gè)是低耦合,一個(gè)是職責(zé)清晰。如果對(duì)此還有懷疑的話(huà),我們可以想象一個(gè)情景,就是負(fù)責(zé)寫(xiě)StudentService的是程序員A,負(fù)責(zé)寫(xiě)StudentRepository的是另一個(gè)程序員B,那么:
針對(duì)程序員A
我(程序員A)只需要關(guān)注業(yè)務(wù)邏輯層面,如果我需要從倉(cāng)儲(chǔ)層拿數(shù)據(jù)庫(kù)的數(shù)據(jù),比如我需要根據(jù)Id獲取學(xué)生實(shí)體,那么我只需要去IStudentRepository找Get(long id)函數(shù)就可以了,至于實(shí)現(xiàn)它的倉(cāng)儲(chǔ)怎么實(shí)現(xiàn)這個(gè)方法我完全不用管,你怎么從數(shù)據(jù)庫(kù)拿數(shù)據(jù)不是我該關(guān)心的事情。
針對(duì)程序員B
我(程序員B)的工作就是實(shí)現(xiàn)IStudentRepository接口的所有方法就行了,簡(jiǎn)單而明確,至于誰(shuí)來(lái)調(diào)用我,我不用管。IStudentRepository里有根據(jù)Id獲取學(xué)生姓名的方法,我實(shí)現(xiàn)了就行,至于業(yè)務(wù)邏輯層拿這個(gè)名字干啥,那不是我要關(guān)心的事情。
這樣看的話(huà)是不是彼此的職責(zé)就清晰多了,更進(jìn)一步再舉個(gè)極端的例子:
比如程序員B是個(gè)實(shí)習(xí)生,整天劃水摸魚(yú),技術(shù)停留在上個(gè)世紀(jì),結(jié)果他寫(xiě)的倉(cāng)儲(chǔ)層讀取數(shù)據(jù)庫(kù)全部用的手寫(xiě)sql語(yǔ)句的方式,極難維護(hù),后來(lái)被領(lǐng)導(dǎo)發(fā)現(xiàn)領(lǐng)了盒飯,公司安排了另一個(gè)程序員C來(lái)重寫(xiě)倉(cāng)儲(chǔ)層,C這時(shí)不需要?jiǎng)悠渌a,只需要新建一個(gè)倉(cāng)儲(chǔ)StudentNewRepository,然后實(shí)現(xiàn)之前的IStudentRepository,C使用Dapper或者EF,寫(xiě)完新的倉(cāng)儲(chǔ)層之后,剩下的只需要在StudentService里改一個(gè)地方就行了:
public StudentService(){_studentRepository = new StudentNewRepository();
}
是不是很清晰,耦合不會(huì)像以前那么重。
其實(shí)對(duì)于這個(gè)小例子來(lái)說(shuō),接口驅(qū)動(dòng)的優(yōu)勢(shì)還不太明顯,但是在系統(tǒng)層面優(yōu)勢(shì)就會(huì)被放大。比如上面換倉(cāng)儲(chǔ)的例子,雖然職責(zé)是清晰了,但是項(xiàng)目里有幾個(gè)Service就需要改幾個(gè)地方,還是很麻煩。
原因就是上面講的,這是一種依賴(lài)關(guān)系,Service要依賴(lài)Repository,有沒(méi)有一種方法可以讓這種控制關(guān)系反轉(zhuǎn)過(guò)來(lái)呢?當(dāng)Service需要使用Repository,有沒(méi)有辦法讓我需要的Repository自己注入到我這里來(lái)?
當(dāng)然有,這就是我們將要實(shí)現(xiàn)的依賴(lài)注入。使用依賴(lài)注入后你會(huì)發(fā)現(xiàn),當(dāng)C寫(xiě)完新的倉(cāng)儲(chǔ)后,業(yè)務(wù)邏輯層(StudentService)是不需要改任何代碼的,所有的Service都不需要一個(gè)一個(gè)去改,直接在注入的時(shí)候修改規(guī)則,不要注入以前老的直接注入新的倉(cāng)儲(chǔ)就可以了。
面向接口后的架構(gòu):
什么是IoC
IoC,全稱(chēng)Inversion of Control,即“控制反轉(zhuǎn)”,是一種設(shè)計(jì)原則,最早由Martin Fowler提出,因?yàn)槠淅碚撎岢鰰r(shí)間和成熟時(shí)間相對(duì)較晚,所以并沒(méi)有被包含在GoF的《設(shè)計(jì)模式》中。
什么是DI
DI,全稱(chēng)Dependency Injection,即依賴(lài)注入,是實(shí)現(xiàn)IoC的其中一種設(shè)計(jì)方法。
其特征是通過(guò)一些技巧,將依賴(lài)的對(duì)象注入到調(diào)用者當(dāng)中。(比如把Repository注入到Service當(dāng)中)
這里說(shuō)的技巧目前主要指的就是引入容器,先把所有會(huì)產(chǎn)生依賴(lài)的對(duì)象統(tǒng)一添加到容器當(dāng)中,比如StudentRepository和StudentService,把分配權(quán)限交給容器,當(dāng)StudentService內(nèi)部需要使用StudentRepository時(shí),這時(shí)不應(yīng)該讓它自己new出來(lái)一個(gè),而是通過(guò)容器,把StudentRepository注入到StudentService當(dāng)中。
這就是名稱(chēng)“依賴(lài)注入”的由來(lái)。
DI和IoC有什么區(qū)別
這是個(gè)老生常談的問(wèn)題了,而且這兩個(gè)名字經(jīng)常在各種大牛和偽大牛的吹逼現(xiàn)場(chǎng)頻繁出現(xiàn) ,聽(tīng)的新手云里霧里,莫名感到神圣不可侵犯。那么DI和IoC是同一個(gè)東西嗎?如果不是,它們又有什么區(qū)別呢?
回答很簡(jiǎn)單:不是一個(gè)東西。
區(qū)別也很簡(jiǎn)單,一句話(huà)概括就是:IoC是一種很寬泛的理念,DI是實(shí)現(xiàn)了IoC的其中一種方法。
說(shuō)到這里我已經(jīng)感覺(jué)到屏幕后的你性感地添了一下嘴唇,囤積好口水,準(zhǔn)備開(kāi)始噴我了。
先別慌,我有證據(jù),我們先來(lái)看下微軟怎么說(shuō):
ASP.NET Core supports the dependency injection (DI) software design pattern, which is a technique for achieving Inversion of Control (IoC) between classes and their dependencies.
地址:https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-2.2
翻譯過(guò)來(lái)就是“ASP.NET Core支持依賴(lài)注入(DI)的軟件設(shè)計(jì)模式,該模式是一種在類(lèi)和它依賴(lài)的對(duì)象之間實(shí)現(xiàn)了控制反轉(zhuǎn)(IoC)的技術(shù)”。
如果有人覺(jué)得辣雞微軟不夠權(quán)威,那我們?nèi)タ聪翴oC以及DI這兩個(gè)概念的發(fā)明人——Martin Fowler怎么說(shuō):
幾位輕量級(jí)容器的作者曾驕傲地對(duì)我說(shuō):這些容器非常有用,因?yàn)樗鼈儗?shí)現(xiàn)了控制反轉(zhuǎn)。這樣的說(shuō)辭讓我深感迷惑:控制反轉(zhuǎn)是框架所共有的特征,如果僅僅因?yàn)槭褂昧丝刂品崔D(zhuǎn)就認(rèn)為這些輕量級(jí)容器與眾不同,就好象在說(shuō)我的轎車(chē)是與眾不同的,因?yàn)樗兴膫€(gè)輪子。
因此,我想我們需要給這個(gè)模式起一個(gè)更能說(shuō)明其特點(diǎn)的名字——”控制反轉(zhuǎn)”這個(gè)名字太泛了,常常讓人有些迷惑。經(jīng)與多位IoC 愛(ài)好者討論之后,我們決定將這個(gè)模式叫做”依賴(lài)注入”(Dependency Injection)。
地址:http://insights.thoughtworkers.org/injection/
Martin Fowler說(shuō)的比較委婉,其實(shí)說(shuō)白了就是建議我們,不要亂用IoC裝逼,IoC是一種設(shè)計(jì)理念,很寬泛,你把程序里的一個(gè)寫(xiě)死的變量改成從配置文件里讀取也是一種控制反轉(zhuǎn)(由程序控制反轉(zhuǎn)為由框架控制),你把這個(gè)配置改成用戶(hù)UI界面的一個(gè)輸入文本框由用戶(hù)輸入也是一種控制反轉(zhuǎn)(由框架控制反轉(zhuǎn)為由用戶(hù)自己控制)。
所以,如果確定討論的模式是DI,那么就表述為DI,還是盡量少用IoC這種寬泛的表達(dá)。
AutoFac
AutoFac是一個(gè)開(kāi)源的輕量級(jí)的DI容器,也是.net下最受大家歡迎的實(shí)現(xiàn)依賴(lài)注入的工具之一,通過(guò)AutoFac我們可以很方便的實(shí)現(xiàn)一些DI的騷操作。
實(shí)戰(zhàn)控制臺(tái)程序依賴(lài)注入
目標(biāo)很簡(jiǎn)單,就是控制臺(tái)程序啟動(dòng)后,將學(xué)生姓名打印出來(lái)。
程序啟動(dòng)流程是,控制臺(tái)主程序調(diào)用Service層,Service層調(diào)用Repository層獲取數(shù)據(jù)(示例項(xiàng)目的倉(cāng)儲(chǔ)層沒(méi)有連接數(shù)據(jù)庫(kù),只是直接造個(gè)假數(shù)據(jù)返回)。
沒(méi)有依賴(lài)注入的情況下,肯定是主程序會(huì)new一個(gè)StudentService,StudentService里會(huì)new一個(gè)StudentRepository,現(xiàn)在引入依賴(lài)注入后,就不應(yīng)該這么new出來(lái)了,而是通過(guò)容器注入,也就是容器會(huì)把StudentRepository自動(dòng)注入到StudentService當(dāng)中。
架構(gòu)
實(shí)體層
學(xué)生實(shí)體類(lèi)StudentEntity:
namespace Ray.EssayNotes.AutoFac.Model{
/// 學(xué)生實(shí)體
public class StudentEntity
{
/// 唯一標(biāo)識(shí)
public long Id { get; set; }
/// 姓名
public string Name { get; set; }
/// 成績(jī)
public int Grade { get; set; }
}
}
倉(cāng)儲(chǔ)層
IStudentRepository接口:
using Ray.EssayNotes.AutoFac.Model;namespace Ray.EssayNotes.AutoFac.Repository.IRepository
{
/// 學(xué)生倉(cāng)儲(chǔ)interface
public interface IStudentRepository
{
string GetName(long id);
}
}
StudentRepository倉(cāng)儲(chǔ)類(lèi):
using Ray.EssayNotes.AutoFac.Model;using Ray.EssayNotes.AutoFac.Repository.IRepository;
namespace Ray.EssayNotes.AutoFac.Repository.Repository
{
///
/// 學(xué)生倉(cāng)儲(chǔ)
///
public class StudentRepository : IStudentRepository
{
public string GetName(long id){
return "學(xué)生張三";//造個(gè)假數(shù)據(jù)返回
}
}
}
Service層
IStudentService接口
namespace Ray.EssayNotes.AutoFac.Service.IService{
///
/// 學(xué)生邏輯處理interface
///
public interface IStudentService
{
string GetStuName(long id);
}
}
StudentService類(lèi):
using Ray.EssayNotes.AutoFac.Repository.IRepository;using Ray.EssayNotes.AutoFac.Repository.Repository;
using Ray.EssayNotes.AutoFac.Service.IService;
namespace Ray.EssayNotes.AutoFac.Service.Service
{
///
/// 學(xué)生邏輯處理
///
public class StudentService : IStudentService
{
private readonly IStudentRepository _studentRepository;
///
/// 構(gòu)造注入
///
///
public StudentService(IStudentRepository studentRepository){
_studentRepository = studentRepository;
}
public string GetStuName(long id){
var stu = _studentRepository.Get(id);
return stu.Name;
}
}
}
其中構(gòu)造函數(shù)是一個(gè)有參的函數(shù),參數(shù)是學(xué)生倉(cāng)儲(chǔ),這個(gè)后面依賴(lài)注入時(shí)會(huì)用。
AutoFac容器
需要先通過(guò)Nuget導(dǎo)入Autofac包:
using System;using System.Reflection;
//
using Autofac;
using Autofac.Core;
//
using Ray.EssayNotes.AutoFac.Repository.IRepository;
using Ray.EssayNotes.AutoFac.Repository.Repository;
using Ray.EssayNotes.AutoFac.Service.IService;
using Ray.EssayNotes.AutoFac.Service.Service;
namespace Ray.EssayNotes.AutoFac.Infrastructure.Ioc
{
///
/// 控制臺(tái)程序容器
///
public static class Container
{
///
/// 容器
///
public static IContainer Instance;
///
/// 初始化容器
///
///
public static void Init(){
//新建容器構(gòu)建器,用于注冊(cè)組件和服務(wù)
var builder = new ContainerBuilder();
//自定義注冊(cè)
MyBuild(builder);
//利用構(gòu)建器創(chuàng)建容器
Instance = builder.Build();
}
///
/// 自定義注冊(cè)
///
///
public static void MyBuild(ContainerBuilder builder){
builder.RegisterType().As();
builder.RegisterType().As();
}
}
}
其中:
public static IContainer Instance
為單例容器
Init()方法
用于初始化容器,即往容器中添加對(duì)象,我們把這個(gè)添加的過(guò)程稱(chēng)為注冊(cè)(Register)。
ContainerBuilder為AutoFac定義的容器構(gòu)造器,我們通過(guò)使用它往容器內(nèi)注冊(cè)對(duì)象。
MyBuild(ContainerBuilder builder)方法
我們具體注冊(cè)的實(shí)現(xiàn)函數(shù)。RegisterType是AutoFac封裝的一種最基本的注冊(cè)方法,傳入的泛型(StudentService)就是我們欲添加到容器的對(duì)象;As函數(shù)負(fù)責(zé)綁定注冊(cè)對(duì)象的暴露類(lèi)型,一般是以其實(shí)現(xiàn)的接口類(lèi)型暴露,這個(gè)暴露類(lèi)型是我們后面去容器內(nèi)查找對(duì)象時(shí)使用的搜索標(biāo)識(shí),我們從容器外部只有通過(guò)暴露類(lèi)型才能找到容器內(nèi)的對(duì)象。
主程序
需要先Nuget導(dǎo)入AutoFac程序包:
using System;//
using Autofac;
//
using Ray.EssayNotes.AutoFac.Infrastructure.Ioc;
using Ray.EssayNotes.AutoFac.Service.IService;
namespace Ray.EssayNotes.AutoFac.ConsoleApp
{
class Program
{
static void Main(string[] args){
Container.Init();//初始化容器,將需要用到的組件添加到容器中
PrintStudentName(10001);
Console.ReadKey();
}
///
/// 輸出學(xué)生姓名
///
///
public static void PrintStudentName(long id){
//從容器中解析出對(duì)象
IStudentService stuService = Container.Instance.Resolve();string name = stuService.GetStuName(id);
Console.WriteLine(name);
}
}
}
進(jìn)入Main函數(shù),先調(diào)用容器的初始化函數(shù),該函數(shù)執(zhí)行成功后,StudentRepository和StudentService就被注冊(cè)到容器中了。
然后調(diào)用打印學(xué)生姓名的函數(shù),其中Resolve()方法是AutoFac封裝的容器的解析方法,傳入的泛型就是之前注冊(cè)時(shí)的暴露類(lèi)型,下面可以詳細(xì)看下這一步到底發(fā)生了哪些事情:
容器根據(jù)暴露類(lèi)型解析對(duì)象
也就是容器會(huì)根據(jù)暴露類(lèi)型IStudentService去容器內(nèi)部找到其對(duì)應(yīng)類(lèi)(即StudentService),找到后會(huì)試圖實(shí)例化一個(gè)對(duì)象出來(lái)。
實(shí)例化StudentService
AutoFac容器在解析StudentService的時(shí)候,會(huì)調(diào)用StudentService的構(gòu)造函數(shù)進(jìn)行實(shí)例化。
構(gòu)造注入
AutoFac容器發(fā)現(xiàn)StudentService的構(gòu)造函數(shù)需要一個(gè)IStudnetRepository類(lèi)型的參數(shù),于是會(huì)自動(dòng)去容器內(nèi)尋找,根據(jù)這個(gè)暴露類(lèi)型找到對(duì)應(yīng)的StudnetRepository后,自動(dòng)將其注入到了StudentService當(dāng)中
經(jīng)過(guò)這幾步,一個(gè)簡(jiǎn)單的基于依賴(lài)注入的程序就完成了。
結(jié)果
我們將控制臺(tái)程序設(shè)置為啟動(dòng)項(xiàng)目,點(diǎn)擊運(yùn)行,如圖調(diào)用成功:
如果把調(diào)試斷點(diǎn)加在容器初始化函數(shù)里,可以很清晰的看到哪些對(duì)象被注冊(cè)到了容器里:
補(bǔ)充
使用控制臺(tái)程序本來(lái)是為了突出容器的概念,但是容易造成一些誤解,DI的最終形態(tài)可以參考源碼里的Api項(xiàng)目和MVC項(xiàng)目,本來(lái)想循序漸進(jìn),先第一章控制臺(tái)引入容器的概念,然后第二章講批量注冊(cè)、注入泛型、生命周期域管理,第三章講Api和MVC項(xiàng)目,最后兩章講下.net core的DI,但是這里還是先說(shuō)下吧:
誤解1:每次添加Service和Repository都要去注冊(cè),不是更麻煩?
其實(shí)是不需要一個(gè)一個(gè)注冊(cè)的,運(yùn)用批量注冊(cè)后容器內(nèi)部的代碼是這樣的,可以直接批量注冊(cè)所有的:
////// .net framework MVC程序容器
///
public static class MvcContainer
{
public static IContainer Instance;
///
/// 初始化容器
///
///
///
public static void Init(Func func = null){
//新建容器構(gòu)建器,用于注冊(cè)組件和服務(wù)
var builder = new ContainerBuilder();
//注冊(cè)組件
MyBuild(builder);
func?.Invoke(builder);
//利用構(gòu)建器創(chuàng)建容器
Instance = builder.Build();
//將AutoFac設(shè)置為系統(tǒng)DI解析器
System.Web.Mvc.DependencyResolver.SetResolver(new AutofacDependencyResolver(Instance));
}
public static void MyBuild(ContainerBuilder builder){
Assembly[] assemblies = Helpers.ReflectionHelper.GetAllAssembliesWeb();
//批量注冊(cè)所有倉(cāng)儲(chǔ) && Service
builder.RegisterAssemblyTypes(assemblies)//程序集內(nèi)所有具象類(lèi)(concrete classes)
.Where(cc => cc.Name.EndsWith("Repository") |//篩選
cc.Name.EndsWith("Service"))
.PublicOnly()//只要public訪(fǎng)問(wèn)權(quán)限的
.Where(cc => cc.IsClass)//只要class型(主要為了排除值和interface類(lèi)型)
.AsImplementedInterfaces();//自動(dòng)以其實(shí)現(xiàn)的所有接口類(lèi)型暴露(包括IDisposable接口)
//注冊(cè)泛型倉(cāng)儲(chǔ)
builder.RegisterGeneric(typeof(BaseRepository<>)).As(typeof(IBaseRepository<>));
//注冊(cè)Controller
Assembly mvcAssembly = assemblies.FirstOrDefault(x => x.FullName.Contains(".NetFrameworkMvc"));
builder.RegisterControllers(mvcAssembly);
}
}
誤解2:每次使用都要解析下,還不如直接new
好吧,其實(shí)也是不需要自己去解析的,最終形態(tài)的Controller入口是這樣的,直接在構(gòu)造函數(shù)里寫(xiě)就行了:
public class StudentController : Controller{
private readonly IStudentService _studentService;
public StudentController(IStudentService studentService){
_studentService = studentService;
}
///
/// 獲取學(xué)生姓名
///
///
///
public string GetStuNameById(long id){
return _studentService.GetStuName(id);
}
}
就是直接在構(gòu)造函數(shù)里注入就可以了。
誤解3:依賴(lài)注入是不是過(guò)度設(shè)計(jì)?
首先DI是一個(gè)設(shè)計(jì)模式(design pattern),其本身完全不存在過(guò)不過(guò)度的問(wèn)題,這完全取決于用的人和怎么用。
另外,在.NET Core中,DI被提到了一個(gè)很重要的地位,如果想要了解.NET Core,理解DI是必不可少的。
推薦閱讀
(點(diǎn)擊標(biāo)題可跳轉(zhuǎn)閱讀)
ASP.NET Core系列之Dependency injection(依賴(lài)注入)
.NET中擴(kuò)展方法和Enumerable
.NET 架構(gòu)開(kāi)發(fā) 應(yīng)知應(yīng)會(huì)
看完本文有收獲?請(qǐng)轉(zhuǎn)發(fā)分享給更多人
關(guān)注「DotNet」加星標(biāo),提升.Net技能?
好文章,我在看??
總結(jié)
以上是生活随笔為你收集整理的service 层注入不同的数据源_.NET 理论基础+实战控制台程序实现AutoFac注入的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 程序员---不要对自己说“不可能”
- 下一篇: 微软内部文件:Longhorn相关工作外