如何在.net6webapi中使用自動(dòng)依賴注入
IOC/DI
IOC(Inversion of Control)控制反轉(zhuǎn):控制反正是一種設(shè)計(jì)思想,旨在將程序中的控制權(quán)從程序員轉(zhuǎn)移到了容器中。容器負(fù)責(zé)管理對象之間的依賴關(guān)系,使得對象不再直接依賴于其他對象,而是通過依賴注入的方式來獲取所需的資源。
DI(Dependency Injection)依賴注入:他是IOC的具體實(shí)現(xiàn)方式之一,使用最為廣泛,DI通過在運(yùn)行時(shí)動(dòng)態(tài)地將某個(gè)依賴關(guān)系抽象為獨(dú)立的組件,提交到容器之中,需要使用時(shí)再由容器注入,提升組件重用的頻率,為系統(tǒng)搭建一個(gè)靈活,可擴(kuò)展的平臺(tái)。
IOC/DI是一種設(shè)計(jì)模式,用于解耦組件之間的依賴關(guān)系。在傳統(tǒng)的編程模式中,組件之間的依賴關(guān)系是硬編碼在代碼中的,這樣會(huì)導(dǎo)致代碼的耦合度很高,難以維護(hù)和發(fā)展。而IOC/DI模式則是通過將組件之間的依賴關(guān)系交給容器來管理,組件不再直接依賴其他組件,而是通過容器來獲取所依賴的對象。這樣可以使組件之間的依賴關(guān)系更加靈活,容器可以根據(jù)需要?jiǎng)討B(tài)地創(chuàng)建和管理組件,從而實(shí)現(xiàn)更好的可維護(hù)性和可擴(kuò)展性。
如何在.net6webapi中使用依賴注入?
首先我們定義一個(gè)服務(wù)接口及對應(yīng)的實(shí)現(xiàn)
public interface ITestServices { int return123(); }
public class TestServices : ITestServices { public int return123() { return 123; } }
然后我們在Program.cs注入服務(wù)實(shí)現(xiàn)
var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddControllers(); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); builder.Services.AddTransient<ITestServices, TestServices>(); var app = builder.Build(); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseHttpsRedirection(); app.UseAuthorization(); app.MapControllers(); app.Run();
值得注意的是依賴注入有三種生命周期
- 作用域(Scoped):在應(yīng)用程序啟動(dòng)時(shí)創(chuàng)建,并在應(yīng)用程序關(guān)閉時(shí)銷毀。這種類型的服務(wù)實(shí)例會(huì)被容器管理,但是只會(huì)被當(dāng)前請求使用。當(dāng)請求結(jié)束時(shí),該服務(wù)實(shí)例會(huì)被銷毀。
- 單例(Singleton):在應(yīng)用程序啟動(dòng)時(shí)創(chuàng)建,并在整個(gè)應(yīng)用程序運(yùn)行期間保持不變。這種類型的服務(wù)實(shí)例會(huì)被容器管理,并且可以被多個(gè)請求共享。
- 瞬時(shí)(Transient):在應(yīng)用程序啟動(dòng)時(shí)創(chuàng)建,并在應(yīng)用程序關(guān)閉時(shí)銷毀。這種類型的服務(wù)實(shí)例不會(huì)被容器管理,也不會(huì)被其他服務(wù)引用。
最后在需要使用的控制器中構(gòu)造函數(shù)注入就可以使用了
[Route("[controller]/[action]")] [ApiController] public class TestController : ControllerBase { private readonly ITestServices _testServices; public TestController(ITestServices testServices) { _testServices= testServices; } [HttpGet] public int Get123() => _testServices.return123(); }
怎么實(shí)現(xiàn)自動(dòng)注入?
依賴注入好歸好,就是每個(gè)服務(wù)都得在Program.cs注入服務(wù)實(shí)現(xiàn),一但服務(wù)多起來,麻煩不說,Program.cs中的代碼更是會(huì)變得凌亂不堪,可能會(huì)有小伙伴說,可以開一個(gè)擴(kuò)展函數(shù)單獨(dú)做注入,但私以為,既然有一種方法可以一勞永逸,何樂而不為呢?
其實(shí)現(xiàn)便是利用.net的高級特性之一,反射
首先我們定義三個(gè)生命周期接口,其對應(yīng)依賴注入的三種生命周期
//瞬時(shí)注入服務(wù)接口 public interface ITransient { } //作用域注入服務(wù)接口 public interface IScoped { } //單例注入服務(wù)接口 public interface ISingleton { }
然后我們定義自動(dòng)注入的擴(kuò)展方法,其為核心實(shí)現(xiàn)
public static IServiceCollection RegisterAllServices(this IServiceCollection services) { //獲取當(dāng)前程序集 var entryAssembly = Assembly.GetEntryAssembly(); //獲取所有類型 //!. null包容運(yùn)算符,當(dāng)你明確知道表達(dá)式的值不為null 使用!.(即null包容運(yùn)算符)可以告知編譯器這是預(yù)期行為,不應(yīng)發(fā)出警告 //例: entryAssembly!.GetReferencedAssemblies() 正常 //entryAssembly.GetReferencedAssemblies() 編譯器判斷entryAssembly有可能為null,變量下方出現(xiàn)綠色波浪線警告 var types = entryAssembly!.GetReferencedAssemblies()//獲取當(dāng)前程序集所引用的外部程序集 .Select(Assembly.Load)//裝載 .Concat(new List<Assembly>() { entryAssembly })//與本程序集合并 .SelectMany(x => x.GetTypes())//獲取所有類 .Distinct();//排重 //三種生命周期分別注冊 Register<ITransient>(types, services.AddTransient, services.AddTransient); Register<IScoped>(types, services.AddScoped, services.AddScoped); Register<ISingleton>(types, services.AddSingleton, services.AddSingleton); return services; } /// <summary> /// 根據(jù)服務(wù)標(biāo)記的生命周期interface,不同生命周期注冊到容器里面 /// </summary> /// <typeparam name="TLifetime">注冊的生命周期</typeparam> /// <param name="types">集合類型</param> /// <param name="register">委托:成對注冊</param> /// <param name="registerDirectly">委托:直接注冊服務(wù)實(shí)現(xiàn)</param> private static void Register<TLifetime>(IEnumerable<Type> types, Func<Type, Type, IServiceCollection> register, Func<Type, IServiceCollection> registerDirectly) { //找到所有標(biāo)記了Tlifetime生命周期接口的實(shí)現(xiàn)類 var tImplements = types.Where(x => x.IsClass && !x.IsAbstract && x.GetInterfaces().Any(tinterface => tinterface == typeof(TLifetime))); //遍歷,挨個(gè)以其他所有接口為key,當(dāng)前實(shí)現(xiàn)為value注冊到容器中 foreach (var t in tImplements) { //獲取除生命周期接口外的所有其他接口 var interfaces = t.GetInterfaces().Where(x => x != typeof(TLifetime)); if (interfaces.Any()) { foreach (var i in interfaces) { register(i, t); } } //有時(shí)需要直接注入實(shí)現(xiàn)類本身 registerDirectly(t); } }
其核心邏輯便是通過反射掃描程序集,當(dāng)掃描到實(shí)現(xiàn)了我們定義的生命周期接口時(shí),為其實(shí)現(xiàn)對應(yīng)的生命周期注入。
注冊這個(gè)服務(wù)
builder.Services.RegisterAllServices();
然后我們就可以通過繼承生命周期接口來實(shí)現(xiàn)自動(dòng)服務(wù)注入
public interface ITestServices { int return123(); }
public class TestServices : ITestServices, ITransient { public int return123() { return 123; } }
接下來無需在Program.cs注入服務(wù)實(shí)現(xiàn)
調(diào)用成功。
到此這篇關(guān)于如何在.net6webapi中實(shí)現(xiàn)自動(dòng)依賴注入的文章就介紹到這了,更多相關(guān).net6webapi自動(dòng)依賴注入內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
ASP.NET延遲調(diào)用或多次調(diào)用第三方Web?API服務(wù)
這篇文章介紹了ASP.NET延遲調(diào)用或多次調(diào)用第三方Web?API服務(wù)的方法,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-10-10使用.NET Core實(shí)現(xiàn)餓了嗎拆紅包功能
這篇文章主要介紹了使用.NET Core實(shí)現(xiàn)餓了嗎拆紅包功能,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-07-07asp.net core實(shí)現(xiàn)文件上傳功能
這篇文章主要為大家詳細(xì)介紹了asp.net core實(shí)現(xiàn)文件上傳功能,怎么做單文件和多文件上傳,感興趣的小伙伴們可以參考一下2016-06-06.net decimal保留指定的小數(shù)位數(shù)(不四舍五入)
大家都知道decimal保留指定位數(shù)小數(shù)的時(shí)候,.NET自帶的方法都是四舍五入的。那么如何讓decimal保留指定位數(shù)小數(shù)的時(shí)候不四舍五入呢,下面通過這篇文中的示例代碼來一起看看吧。2016-12-12.NET5修改配置不重啟自動(dòng)生效的實(shí)現(xiàn)
.NET Core,.NET5默認(rèn)配置都是只加載一次,修改配置時(shí)都需要重啟才能生效,如何能修改即時(shí)生效呢,本文就來介紹一下2021-09-09