全面解析.NET中的依賴注入(DI)
一、依賴注入核心原理
1. 控制反轉(zhuǎn)(IoC)與DI關(guān)系
- 控制反轉(zhuǎn)(IoC):框架控制程序流程,而非開發(fā)者
- 依賴注入(DI):IoC的一種實(shí)現(xiàn)方式,通過外部提供依賴對象
2. .NET DI核心組件
IServiceCollection:服務(wù)注冊容器IServiceProvider:服務(wù)解析器ServiceDescriptor:服務(wù)描述符(包含生命周期信息)
二、服務(wù)生命周期
三種生命周期類型
| 生命周期 | 描述 | 適用場景 |
|---|---|---|
| Transient | 每次請求創(chuàng)建新實(shí)例 | 輕量級(jí)、無狀態(tài)服務(wù) |
| Scoped | 同一作用域內(nèi)共享實(shí)例 | Web請求上下文 |
| Singleton | 全局單例 | 配置服務(wù)、緩存 |
// 注冊示例 services.AddTransient<ITransientService, TransientService>(); services.AddScoped<IScopedService, ScopedService>(); services.AddSingleton<ISingletonService, SingletonService>();
三、DI容器實(shí)現(xiàn)原理
1. 服務(wù)注冊流程
public static IServiceCollection AddTransient<TService, TImplementation>(this IServiceCollection services)
{
// 創(chuàng)建服務(wù)描述符
var descriptor = new ServiceDescriptor(
typeof(TService),
typeof(TImplementation),
ServiceLifetime.Transient);
// 添加到集合
services.Add(descriptor);
return services;
}
2. 服務(wù)解析流程
public object GetService(Type serviceType)
{
// 1. 查找服務(wù)描述符
var descriptor = _descriptors.FirstOrDefault(d => d.ServiceType == serviceType);
// 2. 根據(jù)生命周期創(chuàng)建實(shí)例
if (descriptor.Lifetime == ServiceLifetime.Singleton)
{
if (_singletons.TryGetValue(serviceType, out var instance))
return instance;
instance = CreateInstance(descriptor);
_singletons[serviceType] = instance;
return instance;
}
// ...處理Scoped和Transient
}
四、高級(jí)實(shí)現(xiàn)方法
1. 工廠模式注冊
services.AddTransient<IService>(provider => {
var otherService = provider.GetRequiredService<IOtherService>();
return new ServiceImpl(otherService, "參數(shù)");
});
2. 泛型服務(wù)注冊
services.AddTransient(typeof(IRepository<>), typeof(Repository<>));
3. 多實(shí)現(xiàn)解決方案
// 注冊多個(gè)實(shí)現(xiàn) services.AddTransient<IMessageService, EmailService>(); services.AddTransient<IMessageService, SmsService>(); // 解析時(shí)獲取所有實(shí)現(xiàn) var services = provider.GetServices<IMessageService>();
五、ASP.NET Core中的DI集成
1. 控制器注入
public class HomeController : Controller
{
private readonly ILogger _logger;
public HomeController(ILogger<HomeController> logger)
{
_logger = logger; // 自動(dòng)注入
}
}
2. 視圖注入
@inject IConfiguration Config <p>當(dāng)前環(huán)境: @Config["Environment"]</p>
3. 中間件注入
public class CustomMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger _logger;
public CustomMiddleware(
RequestDelegate next,
ILogger<CustomMiddleware> logger)
{
_next = next;
_logger = logger;
}
public async Task InvokeAsync(HttpContext context)
{
// 使用注入的服務(wù)
_logger.LogInformation("中間件執(zhí)行");
await _next(context);
}
}
六、自定義DI容器實(shí)現(xiàn)
1. 簡易DI容器實(shí)現(xiàn)
public class SimpleContainer : IServiceProvider
{
private readonly Dictionary<Type, ServiceDescriptor> _descriptors;
public SimpleContainer(IEnumerable<ServiceDescriptor> descriptors)
{
_descriptors = descriptors.ToDictionary(x => x.ServiceType);
}
public object GetService(Type serviceType)
{
if (!_descriptors.TryGetValue(serviceType, out var descriptor))
return null;
if (descriptor.ImplementationInstance != null)
return descriptor.ImplementationInstance;
var type = descriptor.ImplementationType ?? descriptor.ServiceType;
return ActivatorUtilities.CreateInstance(this, type);
}
}
2. 屬性注入實(shí)現(xiàn)
public static class PropertyInjectionExtensions
{
public static void AddPropertyInjection(this IServiceCollection services)
{
services.AddTransient<IStartupFilter, PropertyInjectionStartupFilter>();
}
}
public class PropertyInjectionStartupFilter : IStartupFilter
{
public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
{
return builder =>
{
builder.Use(async (context, nextMiddleware) =>
{
var endpoint = context.GetEndpoint();
if (endpoint?.Metadata.GetMetadata<ControllerActionDescriptor>() is { } descriptor)
{
var controller = context.RequestServices.GetRequiredService(descriptor.ControllerTypeInfo);
// 反射實(shí)現(xiàn)屬性注入
InjectProperties(controller, context.RequestServices);
}
await nextMiddleware();
});
next(builder);
};
}
private void InjectProperties(object target, IServiceProvider services)
{
var properties = target.GetType().GetProperties()
.Where(p => p.CanWrite && p.GetCustomAttribute<InjectAttribute>() != null);
foreach (var prop in properties)
{
var service = services.GetService(prop.PropertyType);
if (service != null)
prop.SetValue(target, service);
}
}
}
七、最佳實(shí)踐
1. 服務(wù)設(shè)計(jì)原則
- 遵循顯式依賴原則
- 避免服務(wù)定位 器模式(反模式)
- 保持服務(wù)輕量級(jí)
2. 常見陷阱
// 錯(cuò)誤示例:捕獲Scoped服務(wù)到Singleton中
services.AddSingleton<IBackgroundService>(provider => {
var scopedService = provider.GetRequiredService<IScopedService>(); // 危險(xiǎn)!
return new BackgroundService(scopedService);
});
// 正確做法:使用IServiceScopeFactory
services.AddSingleton<IBackgroundService>(provider => {
var scopeFactory = provider.GetRequiredService<IServiceScopeFactory>();
return new BackgroundService(scopeFactory);
});
八、性能優(yōu)化
1. 避免過度注入
// 不好:注入過多服務(wù)
public class OrderService(
ILogger logger,
IEmailService emailService,
ISmsService smsService,
IRepository repo,
ICache cache,
IConfig config)
{
// ...
}
// 改進(jìn):使用聚合服務(wù)
public class OrderService(
ILogger logger,
INotificationService notification,
IOrderInfrastructure infra)
{
// ...
}
2. 編譯時(shí)注入
[RegisterTransient(typeof(IMyService))]
public class MyService : IMyService
{
// ...
}
// 使用Source Generator自動(dòng)生成注冊代碼
static partial class ServiceRegistration
{
static partial void AddGeneratedServices(IServiceCollection services)
{
services.AddTransient<IMyService, MyService>();
}
}
.NET的依賴注入系統(tǒng)是框架的核心基礎(chǔ)設(shè)施,理解其原理和實(shí)現(xiàn)方式有助于編寫更可測試、更松耦合的應(yīng)用程序。
到此這篇關(guān)于全面解析.NET中的依賴注入(DI)的文章就介紹到這了,更多相關(guān).NET依賴注入DI內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Discuz!NT 3與asp.net 整合的實(shí)例教程
本次整合只針對NETSNS中的代碼做了少許修改,完成了基本的和論壇同步注冊,登陸和注銷,信息獲取,信息修改。為的是給各位Discuz!NT API愛好者做一個(gè)簡單的API事例,供大家參考。2009-11-11
asp.net下讓Gridview鼠標(biāo)滑過光棒變色效果
Gridview光棒效果 鼠標(biāo)滑過2010-07-07
Json數(shù)據(jù)轉(zhuǎn)換list對象實(shí)現(xiàn)思路及代碼
本文為大家詳細(xì)介紹下Json數(shù)據(jù)轉(zhuǎn)換list對象的具體實(shí)現(xiàn),感興趣的朋友可以參考下哈,希望對你有所幫助2013-04-04
.NET獲取枚舉DescriptionAttribute描述信息性能改進(jìn)的多種方法
這篇文章主要介紹了.NET獲取枚舉DescriptionAttribute描述信息性能改進(jìn)的多種方法 的相關(guān)資料,需要的朋友可以參考下2016-01-01
ASP.NET.4.5.1+MVC5.0設(shè)置系統(tǒng)角色與權(quán)限(一)
這篇文章主要介紹了ASP.NET.4.5.1+MVC5.0設(shè)置系統(tǒng)角色與權(quán)限的部分內(nèi)容,后續(xù)我們將繼續(xù)討論這個(gè)話題,希望小伙伴們喜歡。2015-01-01
Server Application Unavailable出現(xiàn)的原因及解決方案小結(jié)
今天在服務(wù)器安裝了個(gè).net 4.0 framework(原本有1.0和2.0的),配置好站點(diǎn)后,選擇版本為4.0,訪問出錯(cuò),asp.net經(jīng)常會(huì)出現(xiàn)這個(gè)問題,這里腳本之家簡單的給整理下2012-05-05
.NET微信小程序用戶數(shù)據(jù)的簽名驗(yàn)證和解密代碼
這篇文章主要介紹了.NET微信小程序用戶數(shù)據(jù)的簽名驗(yàn)證和解密代碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-12-12

