入門系列-依賴注入
依賴注入
ABP的依賴注入系統是基於Microsoft的依賴注入擴充套件庫(Microsoft.Extensions.DependencyInjection nuget包)開發的.因此,它的文件在ABP中也是有效的.
模組化
由於ABP是一個模組化框架,因此每個模組都定義它自己的服務並在它自己的單獨模組類中通過依賴注入進行註冊.例:
public class BlogModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
//在此處注入依賴項
}
}
依照約定的註冊
ABP引入了依照約定的服務註冊.依照約定你無需做任何事,它會自動完成.如果要禁用它,你可以通過重寫PreConfigureServices
方法,設定SkipAutoServiceRegistration
為true
.
public class BlogModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
SkipAutoServiceRegistration = true;
}
}
一旦跳過自動註冊,你應該手動註冊你的服務.在這種情況下,AddAssemblyOf
擴充套件方法可以幫助你依照約定註冊所有服務.例:
public class BlogModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
SkipAutoServiceRegistration = true;
}
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddAssemblyOf<BlogModule>();
}
}
以下部分解釋了約定和配置.
固有的註冊型別
一些特定型別會預設註冊到依賴注入.例子:
- 模組類註冊為singleton.
- MVC控制器(繼承
Controller
或AbpController
)被註冊為transient. - MVC頁面模型(繼承
PageModel
或AbpPageModel
)被註冊為transient. - MVC檢視元件(繼承
ViewComponent
或AbpViewComponent
)被註冊為transient. - 應用程式服務(實現
IApplicationService
介面或繼承ApplicationService
類)註冊為transient. - 儲存庫(實現
IRepository
介面)註冊為transient. - 域服務(實現
IDomainService
介面)註冊為transient.
示例:
public class BlogPostAppService : ApplicationService
{
}
BlogPostAppService
由於它是從已知的基類派生的,因此會自動註冊為transient生命週期.
依賴介面
如果實現這些介面,則會自動將類註冊到依賴注入:
ITransientDependency
註冊為transient生命週期.ISingletonDependency
註冊為singleton生命週期.IScopedDependency
註冊為scoped生命週期.
示例:
public class TaxCalculator : ITransientDependency
{
}
TaxCalculator
因為實現了ITransientDependency
,所以它會自動註冊為transient生命週期.
Dependency 特性
配置依賴注入服務的另一種方法是使用DependencyAttribute
.它具有以下屬性:
Lifetime
: 註冊的生命週期:Singleton,Transient或Scoped.TryRegister
: 設定true
則只註冊以前未註冊的服務.使用IServiceCollection的TryAdd ... 擴充套件方法.ReplaceServices
: 設定true
則替換之前已經註冊過的服務.使用IServiceCollection的Replace擴充套件方法.
示例:
[Dependency(ServiceLifetime.Transient, ReplaceServices = true)]
public class TaxCalculator
{
}
TaxCalculator
類只公開ITaxCalculator
介面.這意味著你只能注入ITaxCalculator
,但不能注入TaxCalculator
或ICalculator
到你的應用程式中.
如果定義了Lifetime
屬性,則Dependency
特性具有比其他依賴介面更高的優先順序.
ExposeServices 特性
ExposeServicesAttribute
用於控制相關類提供了什麼服務.例:
[ExposeServices(typeof(ITaxCalculator))]
public class TaxCalculator: ICalculator, ITaxCalculator, ICanCalculate, ITransientDependency
{
}
依照約定公開的服務
如果你未指定要公開的服務,則ABP依照約定公開服務.以上面定義的TaxCalculator
為例:
- 預設情況下,類本身是公開的.這意味著你可以按
TaxCalculator
類注入它. - 預設情況下,預設介面是公開的.預設介面是由命名約定確定.在這個例子中,
ICalculator
和ITaxCalculator
是TaxCalculator
的預設介面,但ICanCalculate
不是.
組合到一起
只要有意義,特性和介面是可以組合在一起使用的.
[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(ITaxCalculator))]
public class TaxCalculator : ITaxCalculator, ITransientDependency
{
}
手動註冊
在某些情況下,你可能需要向IServiceCollection
手動註冊服務,尤其是在需要使用自定義工廠方法或singleton例項時.在這種情況下,你可以像Microsoft文件描述的那樣直接新增服務.例:
public class BlogModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
//註冊一個singleton例項
context.Services.AddSingleton<TaxCalculator>(new TaxCalculator(taxRatio: 0.18));
//註冊一個從IServiceProvider解析得來的工廠方法
context.Services.AddScoped<ITaxCalculator>(sp => sp.GetRequiredService<TaxCalculator>());
}
}
注入依賴關係
使用已註冊的服務有三種常用方法.
構造方法注入
這是將服務注入類的最常用方法.例如:
public class TaxAppService : ApplicationService
{
private readonly ITaxCalculator _taxCalculator;
public TaxAppService(ITaxCalculator taxCalculator)
{
_taxCalculator = taxCalculator;
}
public void DoSomething()
{
//...使用 _taxCalculator...
}
}
TaxAppService
在構造方法中得到ITaxCalculator
.依賴注入系統在執行時自動提供所請求的服務.
構造方法注入是將依賴項注入類的首選方式.這樣,除非提供了所有構造方法注入的依賴項,否則無法構造類.因此,該類明確的宣告瞭它必需的服務.
屬性注入
Microsoft依賴注入庫不支援屬性注入.但是,ABP可以與第三方DI提供商(例如Autofac)整合,以實現屬性注入.例:
public class MyService : ITransientDependency
{
public ILogger<MyService> Logger { get; set; }
public MyService()
{
Logger = NullLogger<MyService>.Instance;
}
public void DoSomething()
{
//...使用 Logger 寫日誌...
}
}
對於屬性注入依賴項,使用公開的setter宣告公共屬性.這允許DI框架在建立類之後設定它.
屬性注入依賴項通常被視為可選依賴項.這意味著沒有它們,服務也可以正常工作.Logger
就是這樣的依賴項,MyService
可以繼續工作而無需日誌記錄.
為了使依賴項成為可選的,我們通常會為依賴項設定預設/後備(fallback)值.在此示例中,NullLogger用作後備.因此,如果DI框架或你在建立MyService
後未設定Logger屬性,則MyService
依然可以工作但不寫日誌.
屬性注入的一個限制是你不能在建構函式中使用依賴項,因為它是在物件構造之後設定的.
當你想要設計一個預設注入了一些公共服務的基類時,屬性注入也很有用.如果你打算使用構造方法注入,那麼所有派生類也應該將依賴的服務注入到它們自己的構造方法中,這使得開發更加困難.但是,對於非可選服務使用屬性注入要非常小心,因為它使得類的要求難以清楚地看到.
從IServiceProvider解析服務
你可能希望直接從IServiceProvider
解析服務.在這種情況下,你可以將IServiceProvider
注入到你的類並使用GetService
方法,如下所示:
public class MyService : ITransientDependency
{
private readonly IServiceProvider _serviceProvider;
public MyService(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public void DoSomething()
{
var taxCalculator = _serviceProvider.GetService<ITaxCalculator>();
//...
}
}
釋放/處理(Releasing/Disposing)服務
如果你使用了建構函式或屬性注入,則無需擔心釋放服務的資源.但是,如果你從IServiceProvider
解析了服務,在某些情況下,你可能需要注意釋放服務.
ASP.NET Core會在當前HTTP請求結束時釋放所有服務,即使你直接從IServiceProvider
解析了服務(假設你注入了IServiceProvider).但是,在某些情況下,你可能希望釋放/處理手動解析的服務:
- 你的程式碼在AspNet Core請求之外執行,執行者沒有處理服務範圍.
- 你只有對根服務提供者的引用.
- 你可能希望立即釋放和處理服務(例如,你可能會建立太多具有大量記憶體佔用且不想過度使用記憶體的服務).
在任何情況下,你都可以使用這樣的using
程式碼塊來安全地立即釋放服務:
using (var scope = _serviceProvider.CreateScope())
{
var service1 = scope.ServiceProvider.GetService<IMyService1>();
var service2 = scope.ServiceProvider.GetService<IMyService2>();
}
兩個服務在建立的scope被處理時(在using塊的末尾)釋放.
高階特性
IServiceCollection.OnRegistred 事件
你可能想在註冊到依賴注入的每個服務上執行一個操作, 在你的模組的 PreConfigureServices
方法中, 使用 OnRegistred
方法註冊一個回撥(callback) , 如下所示:
public class AppModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
context.Services.OnRegistred(ctx =>
{
var type = ctx.ImplementationType;
//...
});
}
}
ImplementationType
提供了服務型別. 該回撥(callback)通常用於向服務新增攔截器. 例如:
public class AppModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
context.Services.OnRegistred(ctx =>
{
if (ctx.ImplementationType.IsDefined(typeof(MyLogAttribute), true))
{
ctx.Interceptors.TryAdd<MyLogInterceptor>();
}
});
}
}
這個示例判斷一個服務類是否具有 MyLogAttribute
特性, 如果有的話就新增一個 MyLogInterceptor
到攔截器集合中.
注意, 如果服務類公開了多於一個服務或介面,
OnRegistred
回撥(callback)可能被同一服務類多次呼叫. 因此, 較安全的方法是使用Interceptors.TryAdd
方法而不是Interceptors.Add
方法. 請參閱動態代理(dynamic proxying)/攔截器 文件.
第三方提供程式
雖然ABP框架沒有對任何第三方DI提供程式的核心依賴, 但它必須使用一個提供程式來支援動態代理(dynamic proxying)和一些高階特性以便ABP特效能正常工作.
啟動模板中已安裝了Autofac. 更多資訊請參閱 Autofac 整合 文件.
請參閱
相關文章
- 依賴注入系列教程依賴注入
- Semantic Kernel入門系列:透過依賴注入管理物件和外掛依賴注入物件
- Spring系列.依賴注入配置Spring依賴注入
- Play! Framework 系列(三):依賴注入Framework依賴注入
- Gradle入門系列(3):依賴管理Gradle
- Spring原始碼系列:依賴注入-引言Spring原始碼依賴注入
- 擁抱.NET Core系列:依賴注入(1)依賴注入
- 擁抱.NET Core系列:依賴注入(2)依賴注入
- Spring系列第八講 依賴注入之手動注入Spring依賴注入
- Spring原始碼系列:依賴注入(三)-屬性注入Spring原始碼依賴注入
- angular依賴注入Angular依賴注入
- XUnit 依賴注入依賴注入
- Struts 依賴注入依賴注入
- 依賴倒置(DIP)與依賴注入(DI)依賴注入
- 依賴注入?依賴注入是如何實現解耦的?依賴注入解耦
- Spring原始碼系列:依賴注入(二)createBeanSpring原始碼依賴注入Bean
- Spring原始碼系列:依賴注入(一)getBeanSpring原始碼依賴注入Bean
- Java Web系列:Spring依賴注入基礎JavaWebSpring依賴注入
- ASP.NET Core中的依賴注入(2):依賴注入(DI)ASP.NET依賴注入
- [譯] 依賴注入?? 哈??依賴注入
- Angular 依賴注入原理Angular依賴注入
- .Net Core — 依賴注入依賴注入
- 理解 Angular 依賴注入Angular依賴注入
- Spring依賴注入Spring依賴注入
- Spring依賴注入---Spring依賴注入
- 我看依賴注入依賴注入
- webapi - 使用依賴注入WebAPI依賴注入
- 依賴注入是否值得?依賴注入
- 軟體工程入門-輕鬆理解依賴注入 (DI) 和 IoC 容器軟體工程依賴注入
- Spring原始碼系列:依賴注入(四)-總結Spring原始碼依賴注入
- Asp .Net Core 依賴注入依賴注入
- Spring IOC——依賴注入Spring依賴注入
- C# 依賴注入 & MEFC#依賴注入
- Spring 依賴注入 DISpring依賴注入
- 關於依賴注入(typescript)依賴注入TypeScript
- 什麼是依賴注入依賴注入
- .NET8 依賴注入依賴注入
- spring 的依賴注入Spring依賴注入