.NET 自動(dòng)依賴注入神器
在 .NET Core/Web 項(xiàng)目中,手動(dòng)寫一堆 services.AddScoped<...>、AddSingleton<...> 是否讓你頭大?今天給大家介紹一個(gè)神器——Injectio,幫你自動(dòng)掃描并注冊(cè)服務(wù),減少重復(fù)代碼,讓你的依賴注入(DI)更加優(yōu)雅。
什么是 Injectio?
Injectio 是一個(gè) 自動(dòng)服務(wù)注冊(cè)庫,通過 約定(Convention)+ 特性(Attribute) 自動(dòng)掃描并注冊(cè)依賴服務(wù)。
簡(jiǎn)單理解:
- ? 不用手動(dòng)注冊(cè)服務(wù)
- ? 支持 Singleton / Scoped / Transient
- ? 支持工廠方法、模塊注冊(cè)、泛型和 Keyed 服務(wù)
適用于 .NET 6/7/8 Web 或控制臺(tái)項(xiàng)目。
安裝
dotnet add package Injectio
或者添加到 .csproj 文件中
<PackageReference Include="Injectio" PrivateAssets="all" />
PrivateAssets="all"表示這個(gè)包不會(huì)被依賴它的項(xiàng)目引用。
基礎(chǔ)用法
1?? 創(chuàng)建接口和實(shí)現(xiàn)類
public interfaceIMessageService { string Send(string message); } [RegisterSingleton] // 自動(dòng)注冊(cè)為單例 publicclassEmailMessageService : IMessageService { public string Send(string message) { Console.WriteLine($"Email sent: {message}"); return message; } }
2?? 在入口程序中調(diào)用 Injectio
對(duì)于 .NET 6/7/8 最小 API:
using Injectio; var builder = WebApplication.CreateBuilder(args); // ?? 自動(dòng)注冊(cè)項(xiàng)目中的服務(wù)(自動(dòng)生成的)類,可以看截圖 builder.Services.AddInjectioDemo(); var app = builder.Build(); app.MapGet("/", (IMessageService messageService) => { messageService.Send("Hello from Injectio!"); return"Message sent!"; }); app.Run();
或者在控制器中使用
[ApiController] [Route("[controller]/[action]")] publicclassWeatherForecastController : ControllerBase { privatereadonly IMessageService _myService; public WeatherForecastController(IMessageService myService) { _myService = myService; } [HttpGet(Name = "GetWeatherForecast2")] public string Get2() { return _myService.Send("Hello from WeatherForecastController!"); } }
這樣就不用再寫
services.AddScoped<IMessageService, EmailMessageService>()了!
方法注冊(cè)
public class RegistrationModule { [RegisterServices] public static void Register(IServiceCollection services) { services .AddOptions<PollingOption>() .Configure<IConfiguration>((settings, configuration) => configuration.GetSection(PollingOption.SectionName).Bind(settings) ); } }
注冊(cè)特性(Attributes)
在類上添加注冊(cè)特性,源生成器會(huì)自動(dòng)發(fā)現(xiàn)并注冊(cè)服務(wù)。
| 特性 | 說明 |
[RegisterSingleton] |
標(biāo)記為單例服務(wù) |
[RegisterScoped] |
標(biāo)記為作用域服務(wù) |
[RegisterTransient] |
標(biāo)記為瞬態(tài)服務(wù) |
[RegisterServices] |
標(biāo)記方法,用于注冊(cè)服務(wù) |
特性可選屬性
ServiceType:指定注冊(cè)接口ImplementationType:指定實(shí)現(xiàn)類型Factory:使用工廠方法創(chuàng)建實(shí)例Duplicate:重復(fù)注冊(cè)策略(Skip / Replace / Append)Registration:注冊(cè)策略(Self / ImplementedInterfaces / SelfWithInterfaces)
重復(fù)注冊(cè)策略
Skip:已存在的服務(wù)跳過注冊(cè)Replace:替換已有的服務(wù)注冊(cè)Append:在已有服務(wù)后追加注冊(cè)
注冊(cè)策略
Self:將具體類型注冊(cè)為自身ImplementedInterfaces:注冊(cè)為其實(shí)現(xiàn)的接口SelfWithInterfaces:注冊(cè)為自身及實(shí)現(xiàn)的接口
示例
單例服務(wù)
[RegisterSingleton] public class SingletonService : IService { }
指定服務(wù)類型:
[RegisterSingleton(ServiceType = typeof(IService))] public class SingletonService : IService { }
支持 IEnumerable<T> 多服務(wù)解析:
[RegisterSingleton(Duplicate = DuplicateStrategy.Append)] public class SingletonService : IService { }
作用域服務(wù)
[RegisterScoped] public class ScopedService : IService { }
瞬態(tài)服務(wù)
[RegisterTransient] public class TransientService : IService { }
工廠注冊(cè)
[RegisterTransient(Factory = nameof(ServiceFactory))] publicclassFactoryService : IFactoryService { privatereadonly IService _service; public FactoryService(IService service) { _service = service; } public static IFactoryService ServiceFactory(IServiceProvider serviceProvider) { returnnew FactoryService(serviceProvider.GetService<IService>()); } }
開放泛型(Open Generic)
[RegisterSingleton(ImplementationType = typeof(OpenGeneric<>), ServiceType = typeof(IOpenGeneric<>))] public class OpenGeneric<T> : IOpenGeneric<T> { }
版本 5.0+ 支持自注冊(cè)開放泛型:
[RegisterSingleton] public class OpenGeneric<T> : IOpenGeneric<T> { }
泛型特性(需 .NET 7.0+)
[RegisterSingleton<IService>] public class ServiceImplementation : IService { }
Keyed 服務(wù)(需 Microsoft.Extensions.DependencyInjection 8.0+)
[RegisterSingleton<IServiceKeyed>(ServiceKey = "Alpha")] public class ServiceAlphaKeyed : IServiceKeyed { } [RegisterSingleton<IServiceKeyed>(ServiceKey = "Beta")] public class ServiceBetaKeyed : IServiceKeyed { }
使用枚舉注冊(cè):
public enum ServiceType { Alpha, Beta } [RegisterSingleton<IServiceKeyed>(ServiceKey = ServiceType.Alpha)] public class ServiceAlphaTypeKeyed : IServiceKeyed { } [RegisterSingleton<IServiceKeyed>(ServiceKey = ServiceType.Beta)] public class ServiceBetaTypeKeyed : IServiceKeyed { }
使用工廠方法注冊(cè):
[RegisterSingleton<IServiceKeyed>(ServiceKey = "Charlie", Factory = nameof(ServiceFactory))] [RegisterSingleton<IServiceKeyed>(ServiceKey = "Delta", Factory = nameof(ServiceFactory))] public class ServiceFactoryKeyed : IServiceKeyed { public ServiceFactoryKeyed(object? serviceKey) { ServiceKey = serviceKey; } public object? ServiceKey { get; } public static IServiceKeyed ServiceFactory(IServiceProvider serviceProvider, object? serviceKey) { return new ServiceFactoryKeyed(serviceKey); } }
添加到容器
源生成器會(huì)生成一個(gè)擴(kuò)展方法,將所有發(fā)現(xiàn)的服務(wù)注冊(cè)到容器中:
var services = new ServiceCollection(); services.AddInjectioTestsConsole();
自定義擴(kuò)展方法名稱(通過 MSBuild 屬性 InjectioName):
<PropertyGroup> <InjectioName>Library</InjectioName> </PropertyGroup> <ItemGroup> <CompilerVisibleProperty Include="InjectioName" /> </ItemGroup>
使用方法:
var services = new ServiceCollection(); services.AddLibrary();
注冊(cè)標(biāo)簽(Tags)
標(biāo)記服務(wù):
public interface IServiceTag { } [RegisterSingleton(Tags = "Client,FrontEnd")] public class ServiceTag : IServiceTag { }
在注冊(cè)方法中使用標(biāo)簽:
public static class ServiceRegistration { [RegisterServices] public static void Register(IServiceCollection services, ISet<string> tags) { // 根據(jù) tags 條件注冊(cè)服務(wù) } }
添加到容器時(shí)指定標(biāo)簽(不指定則注冊(cè)所有服務(wù)):
var services = new ServiceCollection(); services.AddInjectioTestsLibrary("Client");
?? 總結(jié)
Injectio 讓 .NET 項(xiàng)目的依賴注入變得自動(dòng)化、優(yōu)雅,同時(shí)支持:
- ? 多種生命周期:Singleton / Scoped / Transient
- ? 工廠、模塊、泛型、Keyed 服務(wù)
- ? 標(biāo)簽控制和重復(fù)策略
- ? 最小化手動(dòng)注冊(cè),減少 boilerplate
如果你還在為一堆 AddScoped、AddTransient 頭疼,Injectio 會(huì)是你的救星!
本文來自博客園,作者:四川郭富城,轉(zhuǎn)載請(qǐng)注明原文鏈接:http://www.rzrgm.cn/Andy-Blog/p/19137665

浙公網(wǎng)安備 33010602011771號(hào)