Asp.net core 的依赖注入
依赖注入(DI)是一种在类和其依赖关系之间实现控制反转(IOC)的技术.
这是MSDN上对依赖注入的解释,那么什么是控制反转呢?
控制反转
简单地说,就是本来需要你用程序代码控制的对象的创建和维护,现在都交给第三方。
依赖注入会通过以下方式实现:
- 使用接口或基类将依赖关系实现抽象化。
- 在服务容器中注册依赖关系。
- 将服务注入。框架负责创建依赖关系的实例,并在不再需要时将其释放。
具体在Asp.net core中如何使用,下文将使用Asp.net core内置的依赖注入框架进行讲解。首先是
准备工作
框架有一下几个核心类型:
- IServiceCollection。负责服务的注册
- ServiceDescriptor。存储服务对象的描述信息
- IServiceProvider。服务容器
- IServiceScope。为对象圈定作用域
对象的生命周期:
- 单例 Singleton
- 作用域 Scoped
- 瞬时 Transient
先准备三个类
//MySingletonService.cs
public interface ISingletonService { }
public class MySingletonService:ISingletonService
{
}
//MyScopedService.cs
public interface IScopedService{ }
public class MyScopedService:IScopedService
{
}
//MyTransientService.cs
public interface ITransientService { }
public class MyTransientService:ITransientService
{
}
服务注册
public class Program
{
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
//*常规注册不同生命周期的服务
builder.Services.AddSingleton<ISingletonService, MySingletonService>();
builder.Services.AddScoped<IScopedService, MyScopedService>();
builder.Services.AddTransient<ITransientService, MyTransientService>();
//注册泛型
builder.Services.AddScoped(typeof(IScopedTService), typeof(MyScopedTService));
//尝试注册,避免相同服务重复注册
builder.Services.TryAddScoped<IScopedService, MyScopedService>();
//尝试注册,同一接口注册多个实例
builder.Services.TryAddEnumerable(ServiceDescriptor.Scoped<IScopedService, MyScopedService2>);
//移除注册
builder.Services.RemoveAll<IScopedService>();
//替换第一个注册
builder.Services.Replace(ServiceDescriptor.Singleton<IScopedService,MyScopedService>());
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseAuthorization();
app.MapControllers();
app.Run();
}
}
服务注入
这里介绍三种方式,推荐一般使用第一种,构造函数注入
[ApiController]
[Route("[controller]/[action]")]
public class DIController : ControllerBase
{
//注册单个实例
private readonly IScopedService _scopedService;
public DIController(IScopedService scopedService)
{
_scopedService = scopedService;
}
//注册多个实例
private readonly IEnumerable<IScopedService> _scopedServices;
public DIController(IEnumerable<IScopedService> scopedServices)
{
_scopedServices = scopedServices;
}
[HttpGet]
public void Test()
{
var s = _scopedServices.ToArray();
Console.WriteLine(s[0].GetHashCode());
Console.WriteLine(s[1].GetHashCode());
}
}
如果一个类中只有某一个方法用到该服务,那么可以使用第二种
[HttpGet]
public void Test([FromServices] IScopedService _scopedService)
{
}
最后一种直接从容器中获取实例,一般不使用。但有些情况,比如要在一个单例服务中使用一个scoped服务,由于被注入服务生命周期更长依赖注入失败,此时可以使用
private readonly IServiceProvider _serviceProvider;
public DIController(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
[HttpGet]
public void Test()
{
using (var scope = _serviceProvider.CreateScope())
{
var service = scope.ServiceProvider.GetRequiredService<IScopedService>();
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?