ASP.NET?Core依賴注入(DI)講解
ASP.NET Core的底層設(shè)計支持和使用依賴注入。ASP.NET Core 應(yīng)用程序可以利用內(nèi)置的框架服務(wù)將服務(wù)注入到啟動類的方法中,并且應(yīng)用程序服務(wù)也可以配置注入。由ASP.NET Core 提供的默認服務(wù)容器提供了最小功能集,并不是取代其他容器。
1.淺談依賴注入
依賴注入(Dependency injection,DI)是一種實現(xiàn)對象和依賴者之間松耦合的技術(shù),將類用來執(zhí)行其操作的這些對象以注入的方式提供給該類,而不是直接實例化依賴項或者使用靜態(tài)引用。一般情況,類會通過構(gòu)造函數(shù)聲明器2依賴關(guān)系,允許他們遵循顯示依賴原則。這種方法稱為“構(gòu)造函數(shù)注入”。
當(dāng)類的設(shè)計使用DI思想時,他們的耦合更加松散,因為他們沒有對他們的合作者直接硬編碼的依賴。這遵循“依賴倒置原則”,其中指出,高層模塊不應(yīng)該依賴于底層模塊:兩者都依賴于抽象。
類要求在他們構(gòu)造時向其提供抽象(通常是接口),而不是引用特定的實現(xiàn)。提取接口的依賴關(guān)系和提供接口的實現(xiàn)作為參數(shù)也是“策略設(shè)計模式”的一個示例。
當(dāng)一個類被用來創(chuàng)建類及其相關(guān)的依賴關(guān)系時,這個成為容器(containers),或者稱為控制反轉(zhuǎn)(Inversion of Control, IoC)容器,或者依賴注入容器。容器本質(zhì)上是一個工廠,負責(zé)提供向它請求的類型的實例。如果一個給定類型聲明它具有依賴關(guān)系,并且容器已經(jīng)被配置為其提供依賴關(guān)系,那么它將把創(chuàng)建依賴關(guān)系作為創(chuàng)建請求實例的一部分。除了創(chuàng)建對象的依賴關(guān)系外,容器通常還會管理應(yīng)用程序中對象的生命周期。
ASP.NET Core 包含一個默認支持構(gòu)造函數(shù)注入的簡單內(nèi)置容器,ASP.NET 的容器指的是它管理的類型services,可以在Startup類的ConfigureServices方法中配置內(nèi)置容器的服務(wù)。
2. 使用ASP.NET Core提供的服務(wù)
Startup類的ConfigureServices方法負責(zé)定義應(yīng)用程序?qū)⑹褂玫姆?wù),包括平臺自帶的功能,比如,Entity Framework Core 和 ASP.NET Core MVC。除了IServiceCollection提供的幾個服務(wù)之外,可以使用一些擴展方法(AddDbContext,AddMvc,AddTransient等)向容器添加和注冊額外服務(wù):
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddDbContext<AccessManagementContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"),
providerOptions => providerOptions.EnableRetryOnFailure()));
services.AddTransient<ICompanyServices, CompanyServices>();
}ASP.NET Core 提供的功能和中間件,遵循約定使用一個單一的AddService擴展方法來注冊所有該功能所需的服務(wù)。
3.注冊自己的服務(wù)
我們可以按照 services.AddTransient<ICompanyServices, CompanyServices>(); 這種寫法注冊自己的服務(wù)。第一個范型類型表示將要從容器中請求的類型(通常是一個接口)。第二個范型類型表示將由容器實例化并且用于完成請求的具體類型。
AddTransient 方法用于將抽象類型映射到為每一個需要它的對象分別實例化的具體服務(wù)。為注冊的每一個服務(wù)選擇合適的生命周期很重要,后面會介紹到。
下面是示例是注冊自己的服務(wù):
1.接口
public interface IAccountServices
{
Task<List<AccountViewModel>> GetList();
}2.實現(xiàn)類
public class AccountServices:IAccountServices
{
AccessManagementContext _context;
public AccountServices(AccessManagementContext context)
{
_context = context;//在構(gòu)造函數(shù)中注入
}
public async Task<List<Account>> GetList()
{
try
{
var query = _context.Account.ToListAsync();
return query ;
}
catch (Exception ex)
{
return null;
}
}
}3.在ConfigureServices中注冊自定義的服務(wù)和EF上下文AccessManagementContext
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddDbContext<AccessManagementContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"),
providerOptions => providerOptions.EnableRetryOnFailure()));
services.AddTransient<IAccountServices,AccountServices>();
}4.在Controller構(gòu)造函數(shù)中依賴注入
public class AccountController : Controller
{
private IAccountServices _accountServices;
public AccountController(IAccountServices accountServices)
{
_accountServices = accountServices;
}
// GET: Account
public async Task<ActionResult> Index()
{
var vms = await _accountServices.GetList();
return View(vms);
}4.服務(wù)的生命周期和注冊選項
ASP.NET 服務(wù)生命周期:
- 1.Transient 瞬時
Transient 生命周期服務(wù)在他們每次請求時被創(chuàng)建。適合輕量級,無狀態(tài)的服務(wù)。 - 2.Scoped 作用域
Scoped生命周期在每次請求時創(chuàng)建一次。 - 3.Singleton 單例
Singleton 生命周期服務(wù)在它們第一次請求時創(chuàng)建,并且每個后續(xù)請求使用相同的實例。
服務(wù)可以用多種方式在容器中注冊,除了之前的注冊方法,還可以指定一個工廠,它將被用來創(chuàng)建需要的實例。后面會詳細介紹其他的注冊方法。
下面用一個簡單的示例介紹每個生命周期:
1.創(chuàng)建接口:
namespace MVCTest.Interfaces
{
public interface IOperation
{
/// <summary>
/// 唯一標識
/// </summary>
Guid OperationId { get; }
}
public interface IOperationTransient: IOperation
{
}
public interface IOperationScoped : IOperation
{
}
public interface IOperationSingleton : IOperation
{
}
public interface IOperationInstance : IOperation
{
}
}2.實現(xiàn)類
/// <summary>
/// 實現(xiàn)所有接口
/// </summary>
public class Operation: IOperation, IOperationTransient,
IOperationScoped, IOperationSingleton, IOperationInstance
{
public Operation()
{
OperationId = Guid.NewGuid();
}
public Operation(Guid operationId)
{
if (operationId == null)
{
OperationId = Guid.NewGuid();
}
OperationId = operationId;
}
public Guid OperationId { get; }
}3.注冊到容器
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<IOperationTransient, Operation>();
services.AddScoped<IOperationScoped, Operation>();
services.AddSingleton<IOperationSingleton, Operation>();
services.AddSingleton<IOperationInstance, Operation>();
services.AddTransient<OperationServices, OperationServices>();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}4.上面還注冊了 OperationServices ,用來測試單例模式(單例生命周期服務(wù)中所有請求使用第一次實例化的服務(wù))和 作用域生命周期服務(wù)在每次請求時只創(chuàng)建一次,不管幾個地方用到實例
public class OperationServices
{
public IOperationTransient OperationTransient { get; }
public IOperationScoped OperationScoped { get; }
public IOperationSingleton OperationSingleton { get; }
public IOperationInstance OperationInstance { get; }
public OperationServices(IOperationTransient operationTransient,
IOperationScoped operationScoped,
IOperationSingleton operationSingleton,
IOperationInstance operationInstance)
{
OperationTransient = operationTransient;
OperationScoped = operationScoped;
OperationSingleton = operationSingleton;
OperationInstance = operationInstance;
}
}5.在Controller中使用
public class OperationController : Controller
{
public IOperationTransient OperationTransient { get; }
public IOperationScoped OperationScoped { get; }
public IOperationSingleton OperationSingleton { get; }
public IOperationInstance OperationInstance { get; }
public OperationServices _operationServices;
public OperationController(IOperationTransient operationTransient,
IOperationScoped operationScoped,
IOperationSingleton operationSingleton,
IOperationInstance operationInstance,
OperationServices operationServices)
{
OperationTransient = operationTransient;
OperationScoped = operationScoped;
OperationSingleton = operationSingleton;
OperationInstance = operationInstance;
_operationServices = operationServices;
}
// GET: Operation
public ActionResult Index()
{
ViewBag.OperationTransient = OperationTransient;
ViewBag.OperationScoped = OperationScoped;
ViewBag.OperationSingleton = OperationSingleton;
ViewBag.OperationInstance = OperationInstance;
ViewBag._operationServices = _operationServices;
return View();
}
}6.Index顯示
@{
ViewData["Title"] = "Index";
}
<div>
<h1>Controller Operations</h1>
<h2>OperationTransient: @ViewBag.OperationTransient.OperationId</h2>
<h2>OperationScoped: @ViewBag.OperationScoped.OperationId</h2>
<h2>OperationSingleton: @ViewBag.OperationSingleton.OperationId</h2>
<h2>OperationInstance: @ViewBag.OperationInstance.OperationId</h2>
</div>
<div>
<h1>Services Operations</h1>
<h2>OperationTransient: @ViewBag._operationServices.OperationTransient.OperationId</h2>
<h2>OperationScoped: @ViewBag._operationServices.OperationScoped.OperationId</h2>
<h2>OperationSingleton: @ViewBag._operationServices.OperationSingleton.OperationId</h2>
<h2>OperationInstance: @ViewBag._operationServices.OperationInstance.OperationId</h2>
</div>7.運行結(jié)果

可以看到,單例生命周期服務(wù)每一次請求的標識一樣。作用域生命周期的服務(wù),在一次請求中使用的同一個實例,第二次請求創(chuàng)建新的實例。
5.請求服務(wù)
來自HttpContext的一次ASP.NET 請求中,可用的服務(wù)是通過RequestServices集合公開的。
請求服務(wù)將你配置的服務(wù)和請求描述為應(yīng)用程序的一部分。在子的對象指定依賴之后,這些滿足要求的對象可通過查找RequestServices中對應(yīng)的類型得到,而不是ApplicationServices。
6.設(shè)計依賴注入服務(wù)
在自定義的服務(wù)中,避免使用靜態(tài)方法和直接實例化依賴的類型,而是通過依賴注入請求它。(New is Glue)
如果類有太多的依賴關(guān)系被注入時,通常表明你的類試圖做的太多(違反了單一職責(zé)原則),需要轉(zhuǎn)移一些職責(zé)。
同樣,Controller類應(yīng)該重點關(guān)注UI,因此業(yè)務(wù)邏輯和數(shù)據(jù)訪問等細節(jié)應(yīng)該在其他類中。
7.使用Autofac容器
到此這篇關(guān)于ASP.NET Core依賴注入(DI)的文章就介紹到這了。希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
動態(tài)加載用戶控件至DataList并為用戶控件賦值實例演示
本文借用使用通用的新聞例子演示動態(tài)加載用戶控件至DataList并為用戶控件賦值,感興趣的朋友可以了解下2013-01-01
ASP.NET?Core擴展庫ServiceStack.Redis用法介紹
這篇文章介紹了ASP.NET?Core擴展庫ServiceStack.Redis的用法,文中通過示例代碼介紹的非常詳細。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-02-02
asp.net StreamReader 創(chuàng)建文件的實例代碼
這篇文章介紹了asp.net StreamReader 創(chuàng)建文件的實例代碼,有需要的朋友可以參考一下2013-07-07
如何在ASP.NET Core中使用ViewComponent
這篇文章主要介紹了如何在ASP.NET Core中使用ViewComponent,幫助大家更好的理解和學(xué)習(xí)使用.net技術(shù),感興趣的朋友可以了解下2021-04-04
ASP.NET仿新浪微博下拉加載更多數(shù)據(jù)瀑布流效果
本篇文章介紹了如何實現(xiàn)下拉加載更多數(shù)據(jù)瀑布流的效果,這種效果最近很流行,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2015-07-07

