程序员的知识教程库

网站首页 > 教程分享 正文

ASP.NET Core 优雅的获取IServiceProvider

henian88 2025-05-08 00:58:14 教程分享 3 ℃ 0 评论

在 ASP.NET Core 中,IServiceProvider 是依赖注入的核心接口,用于解析服务实例。可以通过多种方式获取 IServiceProvider,但每种方式的适用场景和行为可能有所不同。下面将详细介绍几种常见的获取方式,并分析它们之间的区别。


创建依赖

//1. 定义服务接口和实现类
public interface IDateTime
{
DateTime Now { get; }
}
public class SystemDateTime : IDateTime
{
public DateTime Now => DateTime.Now;
}
//2.注入服务
builder.Services.AddSingleton<IDateTime, SystemDateTime>();
var app = builder.Build();
//Net分享,欢迎关注!

1. 通过构造函数注入

这是最常见的方式之一,适用于需要在整个类中使用 IServiceProvider 的场景。

public classWeatherForecastController : ControllerBase
{
privatereadonly IServiceProvider _serviceProvider;

public WeatherForecastController(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
[HttpGet(Name = "GetWeatherForecast")]
public bool Get()
{
var service = _serviceProvider.GetService<IDateTime>();
// 使用服务
Console.WriteLine( "NetShare:"+service.Now);
returntrue;
}
}

特点:

  • o 优点:简单直观,符合依赖注入的设计原则。
  • o 缺点:可能会导致对 IServiceProvider 的过度依赖(即服务定位器模式),破坏显式依赖声明的原则。

2. 通过 HttpContext.RequestServices

在控制器或中间件中,可以通过 HttpContext.RequestServices 获取当前请求作用域内的 IServiceProvider

public classWeatherForecastController : ControllerBase
{
privatereadonly IHttpContextAccessor _httpContextAccessor;

public WeatherForecastController(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}

[HttpGet(Name = "GetWeatherForecast")]
public bool Get()
{
var serviceProvider = _httpContextAccessor.HttpContext.RequestServices;
var service = serviceProvider.GetService<IDateTime>();
// 使用服务
Console.WriteLine("NetShare:" + service.Now);
returntrue;
}
}

特点:

  • o 优点:适合在 HTTP 请求上下文中使用,确保获取的服务是当前请求作用域内的实例。
  • o 缺点:需要注入 IHttpContextAccessor,增加了间接依赖。
//需要注册
builder.Services.AddTransient<IHttpContextAccessor, HttpContextAccessor>();

3. 通过 IServiceScopeFactory

如果需要手动创建作用域并获取服务,可以使用 IServiceScopeFactory

public classWeatherForecastController : ControllerBase
{
privatereadonly IServiceScopeFactory _scopeFactory;

public WeatherForecastController(IServiceScopeFactory scopeFactory)
{
_scopeFactory = scopeFactory;
}

[HttpGet(Name = "GetWeatherForecast")]
public bool Get()
{
using (var scope = _scopeFactory.CreateScope())
{
var serviceProvider = scope.ServiceProvider;
var service = serviceProvider.GetService<IDateTime>();
// 使用服务
Console.WriteLine("NetShare:" + service.Now);
}
returntrue;
}
}

特点:

  • o 优点:适合需要手动控制作用域的场景,例如在后台任务中使用依赖注入。
  • o 缺点:需要显式管理作用域的生命周期。

4. 通过 WebApplication

WebApplication 是应用启动时创建的全局 IServiceProvider,通常用于获取单例服务。

builder.Services.AddSingleton<IDateTime, SystemDateTime>();

var app = builder.Build();

using (var scope = app.Services.CreateScope())
{
//Net分享,欢迎关注!
var myService = scope.ServiceProvider.GetRequiredService<IDateTime>();
// 使用服务
Console.WriteLine("NetShare:" + myService.Now);
}

特点:

  • o 优点:适用于需要在应用生命周期外访问服务的场景(如程序启动时的初始化逻辑)。
  • o 缺点:无法获取与请求相关的服务实例。

总结对比

方式
适用场景
是否支持请求作用域
生命周期管理
构造函数注入
普通类中使用
外部管理
HttpContext.RequestServices
HTTP 请求上下文中使用
自动管理
WebApplication
应用启动时或全局范围内使用
全局单例
IServiceScopeFactory
需要手动创建作用域的场景
需要手动管理

注意事项

  1. 1. 避免滥用服务定位器模式
    尽量通过构造函数注入显式声明依赖,而不是通过 IServiceProvider 动态获取服务。这有助于提高代码的可读性和可维护性。
  2. 2. 正确管理作用域
    如果使用 IServiceScopeFactory 创建作用域,请确保及时释放资源,避免内存泄漏。
  3. 3. 区分全局和请求作用域
    在多线程或后台任务中,不要直接使用 HttpContext.RequestServices,因为它可能与当前线程无关。!

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表