首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >ASP.NET Core 优雅的获取IServiceProvider

ASP.NET Core 优雅的获取IServiceProvider

作者头像
郑子铭
发布于 2025-05-17 13:07:00
发布于 2025-05-17 13:07:00
1.3K0
举报

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

创建依赖

代码语言:javascript
复制
//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 的场景。

代码语言:javascript
复制
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;
    }
}

特点:

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

2. 通过 HttpContext.RequestServices

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

代码语言:javascript
复制
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;
    }
}

特点:

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

3. 通过 IServiceScopeFactory

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

代码语言:javascript
复制
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;
    }
}

特点:

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

4. 通过 WebApplication

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

代码语言:javascript
复制
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);
}

特点:

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

总结对比

方式

适用场景

是否支持请求作用域

生命周期管理

构造函数注入

普通类中使用

否

外部管理

HttpContext.RequestServices

HTTP 请求上下文中使用

是

自动管理

WebApplication

应用启动时或全局范围内使用

否

全局单例

IServiceScopeFactory

需要手动创建作用域的场景

是

需要手动管理

注意事项
  1. 1. 避免滥用服务定位器模式 尽量通过构造函数注入显式声明依赖,而不是通过 IServiceProvider 动态获取服务。这有助于提高代码的可读性和可维护性。
  2. 2. 正确管理作用域 如果使用 IServiceScopeFactory 创建作用域,请确保及时释放资源,避免内存泄漏。
  3. 3. 区分全局和请求作用域 在多线程或后台任务中,不要直接使用 HttpContext.RequestServices,因为它可能与当前线程无关。
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-05-17,如有侵权请联系 cloudcommunity@tencent.com 删除
目录
  • 创建依赖
  • 1. 通过构造函数注入
  • 2. 通过 HttpContext.RequestServices
  • 3. 通过 IServiceScopeFactory
  • 4. 通过 WebApplication
  • 总结对比
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档