ASP.NET Core依赖注入解读amp;使用Autofac替代实现
1. 前言
關于IoC模式(控制反轉)和DI技術(依賴注入),我們已經見過很多的探討,這里就不再贅述了。比如說必看的Martin Fowler《IoC 容器和 Dependency Injection 模式》,相關資料鏈接都附于文章末尾。其中我非常贊同Artech的說法"控制更多地體現為一種流程的控制",而依賴注入技術讓我們的應用程序實現了松散耦合。
ASP.NET Core本身已經集成了一個輕量級的IOC容器,開發者只需要定義好接口后,在Startup.cs的ConfigureServices方法里使用對應生命周期的綁定方法即可,常見方法如下
services.AddTransient<IApplicationService,ApplicationService>services.AddScoped<IApplicationService,ApplicationService>
services.AddSingleton<IApplicationService,ApplicationService>
對于上述的三種DI注入方式,官方也給出了詳細的解釋,我來簡單翻譯一下
Transient
Transient 服務在每次請求時被創建,它最好被用于輕量級無狀態服務(如我們的Repository和ApplicationService服務)Scoped
Scoped 服務在每次請求時被創建,生命周期橫貫整次請求Singleton
顧名思義,Singleton(單例) 服務在第一次請求時被創建(或者當我們在ConfigureServices中指定創建某一實例并運行方法),其后的每次請求將沿用已創建服務。如果開發者的應用需要單例服務情景,請設計成允許服務容器來對服務生命周期進行操作,而不是手動實現單例設計模式然后由開發者在自定義類中進行操作。
在這之后,我們便可以將服務通過構造函數注入或者是屬性注入的方式注入到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中定義其實現類。這里為了直觀顯示每次請求的返回值,采取如下代碼
? ?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; //#構造函數注入//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>
之后我們打開兩個瀏覽器,分別刷新數次,也只會發現“TransientItem”和“ScopedItem”的數值不斷變化,“SingletonItem”欄的數值是不會有任何變化的,這就體現出單例模式的作用了,示例圖如下
但是這好像還不夠,要知道我們的Scoped的解讀是“生命周期橫貫整次請求”,但是現在演示起來和Transient好像沒有什么區別(因為兩個頁面每次瀏覽器請求仍然是獨立的,并不包含于一次中),所以我們采用以下代碼來演示下(同一請求源)
@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 調試運行,可以發現“ScopedItem”在同一請求源中是不會發生變化的,但是“TransientItem”依然不斷變化,理論仍然是支持的
3. Autofac實現和自定義實現擴展方法
除了ASP.NETCore自帶的IOC容器外,我們還可以使用其他成熟的DI框架,如Autofac,StructureMap等(筆者只用過Unity,Ninject和Castle,Castle也是使用ABP時自帶的)。
3.1 安裝Autofac
首先在project.json的dependency節點中加入Autofac.Extensions.DependencyInjection引用,目前最新版本是4.0.0-rc3-309
3.2 創建容器并注冊依賴
在Startup.cs中創建一個public IContainer ApplicationContainer { get; private set; }對象,并把ConfigureServices返回類型改為IServiceProvider,然后復制以下代碼進去,也可以實現相關功能
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);值得注意的幾點:
創建Autofac容器時不要忘了將ConfigureServices的返回值修改為IServiceProvider
對應ASP.NET Core提及的不同的生命周期,Autofac也定義了對應的擴展方法,如InstancePerLifetimeScope等,默認為Transient模式,包括EntityFramwork等Context也是該種模式
Autofac Core不支持從View中注入,但是可以和ASP.NET Core自帶IOC容器配合使用
Autofac Core版本和傳統的ASP.NET MVC項目版本的區別
4. 參考鏈接
IoC 容器和 Dependency Injection 模式
控制反轉—維基百科
DependencyInjection-GitHub
ASP.NET Core中的依賴注入(4): 構造函數的選擇與服務生命周期管理
Dependency Injectionf!
原文地址:http://www.cnblogs.com/Wddpct/p/5764511.html
.NET社區新聞,深度好文,微信中搜索dotNET跨平臺或掃描二維碼關注
總結
以上是生活随笔為你收集整理的ASP.NET Core依赖注入解读amp;使用Autofac替代实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Asp.net core中Migrati
- 下一篇: 在离线环境中发布.NET Core至Wi