平时做技术实践时,很多问题不是概念不会,而是细节没串起来。拿“全面解析.NET中的依赖注入(DI)”来说,它看着像小点,放到项目里常会牵出环境、配置、兼容性和维护成本。下面按实际采用顺序,把思路、关键写法和容易踩坑的地方讲清楚,便于大家直接对照操作。
IServiceCollection:服务注册容器IServiceProvider:服务解析器ServiceDescriptor:服务描述符(包含生命周期信息)三种生命周期类型
| 生命周期 | 描述 | 适用场景 |
|---|---|---|
| Transient | 每次请求新建新实例 | 轻量级、无状态服务 |
| Scoped | 同一作用域内共享实例 | Web请求上下文 |
| Singleton | 全局单例 | 设置服务、缓存 |
// 注册示例
services.AddTransient<ITransientService, TransientService>();
services.AddScoped<IScopedService, ScopedService>();
services.AddSingleton<ISingletonService, SingletonService>();
public static IServiceCollection AddTransient<TService, TImplementation>(this IServiceCollection services)
{
// 创建服务描述符
var descriptor = new ServiceDescriptor(
typeof(TService),
typeof(TImplementation),
ServiceLifetime.Transient);
// 添加到集合
services.Add(descriptor);
return services;
}
public object GetService(Type serviceType)
{
// 1. 查找服务描述符
var descriptor = _descriptors.FirstOrDefault(d => d.ServiceType == serviceType);
// 2. 根据生命周期创建实例
if (descriptor.Lifetime == ServiceLifetime.Singleton)
{
if (_singletons.TryGetValue(serviceType, out var instance))
return instance;
instance = CreateInstance(descriptor);
_singletons[serviceType] = instance;
return instance;
}
// ...处理Scoped和Transient
}
services.AddTransient<IService>(provider => {
var otherService = provider.GetRequiredService<IOtherService>();
return new ServiceImpl(otherService, "参数");
});
services.AddTransient(typeof(IRepository<>), typeof(Repository<>));
// 注册多个实现
services.AddTransient<IMessageService, EmailService>();
services.AddTransient<IMessageService, SmsService>();
// 解析时获取所有实现
var services = provider.GetServices<IMessageService>();
public class HomeController : Controller
{
private readonly ILogger _logger;
public HomeController(ILogger<HomeController> logger)
{
_logger = logger; // 自动注入
}
}
@inject IConfiguration Config
<p>当前环境: @Config["Environment"]</p>
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)
{
// 使用注入的服务
_logger.LogInformation("中间件执行");
await _next(context);
}
}
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);
}
}
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);
// 反射实现属性注入
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);
}
}
}
// 错误示例:捕获Scoped服务到Singleton中
services.AddSingleton<IBackgroundService>(provider => {
var scopedService = provider.GetRequiredService<IScopedService>(); // 危险!
return new BackgroundService(scopedService);
});
// 正确做法:使用IServiceScopeFactory
services.AddSingleton<IBackgroundService>(provider => {
var scopeFactory = provider.GetRequiredService<IServiceScopeFactory>();
return new BackgroundService(scopeFactory);
});
// 不好:注入过多服务
public class OrderService(
ILogger logger,
IEmailService emailService,
ISmsService smsService,
IRepository repo,
ICache cache,
IConfig config)
{
// ...
}
// 改进:使用聚合服务
public class OrderService(
ILogger logger,
INotificationService notification,
IOrderInfrastructure infra)
{
// ...
}
[RegisterTransient(typeof(IMyService))]
public class MyService : IMyService
{
// ...
}
// 使用Source Generator自动生成注册代码
static partial class ServiceRegistration
{
static partial void AddGeneratedServices(IServiceCollection services)
{
services.AddTransient<IMyService, MyService>();
}
}
从实现思路看,.NET的依赖注入系统是框架的核心基础设施,理解其原理和实现方法有助于编写更可测试、更松耦合的应用程序。
到此这篇关于全面解析.NET中的依赖注入(DI)的文章就介绍到这了,更多相关.NET依赖注入DI内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多兼容脚本之家!