ASP.NET Core依赖注入解读amp;使用Autofac替代实现
1. 前言
關(guān)于IoC模式(控制反轉(zhuǎn))和DI技術(shù)(依賴注入),我們已經(jīng)見過很多的探討,這里就不再贅述了。比如說必看的Martin Fowler《IoC 容器和 Dependency Injection 模式》,相關(guān)資料鏈接都附于文章末尾。其中我非常贊同Artech的說法"控制更多地體現(xiàn)為一種流程的控制",而依賴注入技術(shù)讓我們的應(yīng)用程序?qū)崿F(xiàn)了松散耦合。
ASP.NET Core本身已經(jīng)集成了一個輕量級的IOC容器,開發(fā)者只需要定義好接口后,在Startup.cs的ConfigureServices方法里使用對應(yīng)生命周期的綁定方法即可,常見方法如下
services.AddTransient<IApplicationService,ApplicationService>services.AddScoped<IApplicationService,ApplicationService>
services.AddSingleton<IApplicationService,ApplicationService>
對于上述的三種DI注入方式,官方也給出了詳細(xì)的解釋,我來簡單翻譯一下
Transient
Transient 服務(wù)在每次請求時被創(chuàng)建,它最好被用于輕量級無狀態(tài)服務(wù)(如我們的Repository和ApplicationService服務(wù))Scoped
Scoped 服務(wù)在每次請求時被創(chuàng)建,生命周期橫貫整次請求Singleton
顧名思義,Singleton(單例) 服務(wù)在第一次請求時被創(chuàng)建(或者當(dāng)我們在ConfigureServices中指定創(chuàng)建某一實例并運(yùn)行方法),其后的每次請求將沿用已創(chuàng)建服務(wù)。如果開發(fā)者的應(yīng)用需要單例服務(wù)情景,請設(shè)計成允許服務(wù)容器來對服務(wù)生命周期進(jìn)行操作,而不是手動實現(xiàn)單例設(shè)計模式然后由開發(fā)者在自定義類中進(jìn)行操作。
在這之后,我們便可以將服務(wù)通過構(gòu)造函數(shù)注入或者是屬性注入的方式注入到Controller,View(通過使用@inject),甚至是Filter中(以前使用Unity將依賴注入到Filter真是一種痛苦)。話不多說,先來體驗一把
Tips:Startup.cs是什么,詳見ASP.NET Core 介紹和項目解讀
2. ASP.NET Core 中的DI方式
大多項目舉例依賴注入的生命周期演示時,都會采取可變Guid來作為返回顯示,此次示例也會這樣處理。我們先定義一個IGuidAppService接口,里面定義基接口和三種注入模式的接口
? ?public interface IGuidAppService{ ? ? ? ?? ? ? ? Guid GuidItem();} ?
?
?
? ?public interface IGuidTransientAppService : IGuidAppService{} ? ?
? ?
? ?public interface IGuidScopedAppService : IGuidAppService{} ?
? ?
? ??public interface IGuidSingletonAppService : IGuidAppService{}
同樣的,在GuidAppService中定義其實現(xiàn)類。這里為了直觀顯示每次請求的返回值,采取如下代碼
? ?public class GuidAppServiceBase : IGuidAppService ? ?{ ? ? ?? ? ??private readonly Guid _item; ? ? ? ?public GuidAppServiceBase(){_item = Guid.NewGuid();} ? ?
? ? ??
? ? ???public Guid GuidItem(){ ? ? ? ?
? ? ???? ?return _item;}} ? ?
? ? ???? ?public class GuidTransientAppService : GuidAppServiceBase, IGuidTransientAppService ? ?{} ? ?
? ? ???? ?public class GuidScopedAppService : GuidAppServiceBase, IGuidScopedAppService ? ?{} ? ?
? ? ???? ?public class GuidSingletonAppService : GuidAppServiceBase, IGuidSingletonAppService ? ?{}
最后是Controller和View視圖的代碼
? ?public class HomeController : Controller{ ? ? ?? ??private readonly IGuidTransientAppService _guidTransientAppService; //#構(gòu)造函數(shù)注入//private ?IGuidTransientAppService _guidTransientAppService { get; } #屬性注入private readonly IGuidScopedAppService _guidScopedAppService; ? ?
? ?? ? ?private readonly IGuidSingletonAppService _guidSingletonAppService; ? ? ? ?public HomeController(IGuidTransientAppService guidTransientAppService, ? ? ? ? ? ?IGuidScopedAppService guidScopedAppService, IGuidSingletonAppService guidSingletonAppService) ? ?
? ?{_guidTransientAppService = guidTransientAppService;_guidScopedAppService = guidScopedAppService;_guidSingletonAppService = guidSingletonAppService;} ? ?
? ?? ? public IActionResult Index() ?
? ? ? ??{ViewBag.TransientItem = _guidTransientAppService.GuidItem();ViewBag.ScopedItem = _guidScopedAppService.GuidItem();ViewBag.SingletonItem = _guidSingletonAppService.GuidItem(); ? ? ? ?
? ?? ? ?? ?return View();}} ? ?<div class="row"><div ><h2>GuidItem Shows</h2><h3>TransientItem: @ViewBag.TransientItem</h3><h3>ScopedItem: @ViewBag.ScopedItem</h3><h3>SingletonItem: @ViewBag.SingletonItem</h3></div> </div>
之后我們打開兩個瀏覽器,分別刷新數(shù)次,也只會發(fā)現(xiàn)“TransientItem”和“ScopedItem”的數(shù)值不斷變化,“SingletonItem”欄的數(shù)值是不會有任何變化的,這就體現(xiàn)出單例模式的作用了,示例圖如下
但是這好像還不夠,要知道我們的Scoped的解讀是“生命周期橫貫整次請求”,但是現(xiàn)在演示起來和Transient好像沒有什么區(qū)別(因為兩個頁面每次瀏覽器請求仍然是獨(dú)立的,并不包含于一次中),所以我們采用以下代碼來演示下(同一請求源)
@using DependencyInjection.IApplicationService @inject IGuidTransientAppService TransientAppService @inject IGuidScopedAppService GuidScopedAppServic @inject IGuidSingletonAppService GuidSingletonAppService<div class="row"><div><h2>GuidItem Shows</h2><h3>TransientItem: @TransientAppService.GuidItem()</h3><h3>ScopedItem: @GuidScopedAppServic.GuidItem()</h3><h3>SingletonItem: @GuidSingletonAppService.GuidItem()</h3></div></div>@{ViewData["Title"] = "Home Page"; }@Html.Partial("GuidItemPartial")@Html.Partial("GuidItemPartial")依然是 Ctrl+F5 調(diào)試運(yùn)行,可以發(fā)現(xiàn)“ScopedItem”在同一請求源中是不會發(fā)生變化的,但是“TransientItem”依然不斷變化,理論仍然是支持的
3. Autofac實現(xiàn)和自定義實現(xiàn)擴(kuò)展方法
除了ASP.NETCore自帶的IOC容器外,我們還可以使用其他成熟的DI框架,如Autofac,StructureMap等(筆者只用過Unity,Ninject和Castle,Castle也是使用ABP時自帶的)。
3.1 安裝Autofac
首先在project.json的dependency節(jié)點中加入Autofac.Extensions.DependencyInjection引用,目前最新版本是4.0.0-rc3-309
3.2 創(chuàng)建容器并注冊依賴
在Startup.cs中創(chuàng)建一個public IContainer ApplicationContainer { get; private set; }對象,并把ConfigureServices返回類型改為IServiceProvider,然后復(fù)制以下代碼進(jìn)去,也可以實現(xiàn)相關(guān)功能
var builder = new ContainerBuilder();//注意以下寫法builder.RegisterType<GuidTransientAppService>().As<IGuidTransientAppService>(); builder.RegisterType<GuidScopedAppService>().As<IGuidScopedAppService>().InstancePerLifetimeScope(); builder.RegisterType<GuidSingletonAppService>().As<IGuidSingletonAppService>().SingleInstance();builder.Populate(services); this.ApplicationContainer = builder.Build();return new AutofacServiceProvider(this.ApplicationContainer);值得注意的幾點:
創(chuàng)建Autofac容器時不要忘了將ConfigureServices的返回值修改為IServiceProvider
對應(yīng)ASP.NET Core提及的不同的生命周期,Autofac也定義了對應(yīng)的擴(kuò)展方法,如InstancePerLifetimeScope等,默認(rèn)為Transient模式,包括EntityFramwork等Context也是該種模式
Autofac Core不支持從View中注入,但是可以和ASP.NET Core自帶IOC容器配合使用
Autofac Core版本和傳統(tǒng)的ASP.NET MVC項目版本的區(qū)別
4. 參考鏈接
IoC 容器和 Dependency Injection 模式
控制反轉(zhuǎn)—維基百科
DependencyInjection-GitHub
ASP.NET Core中的依賴注入(4): 構(gòu)造函數(shù)的選擇與服務(wù)生命周期管理
Dependency Injectionf!
原文地址:http://www.cnblogs.com/Wddpct/p/5764511.html
.NET社區(qū)新聞,深度好文,微信中搜索dotNET跨平臺或掃描二維碼關(guān)注
總結(jié)
以上是生活随笔為你收集整理的ASP.NET Core依赖注入解读amp;使用Autofac替代实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Asp.net core中Migrati
- 下一篇: 使用VS Code开发调试.NET Co