前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >揭秘 .Net Core 中的 IServiceProvider

揭秘 .Net Core 中的 IServiceProvider

作者头像
郑子铭
发布2025-01-11 19:31:42
发布2025-01-11 19:31:42
8000
代码可运行
举报
运行总次数:0
代码可运行

在本文中,我们将全面了解IServiceProvider

.NET Core中的IServiceProvider接口是依赖注入(DI)系统的核心部分。它定义了一种检索服务对象的机制,这些服务对象是由依赖注入容器管理的类型的实例。理解IServiceProvider的工作原理以及如何有效地使用它,对于构建模块化且易于维护的应用程序至关重要。

关键概念

  • 服务提供程序:IServiceProvider接口提供了一种从依赖注入容器中获取服务实例的方式。它有一个名为GetService的方法,该方法用于检索指定类型的服务对象。
  • 服务生命周期:服务的生命周期决定了服务实例可被重复使用的时长。常见的生命周期如下:
    • 瞬态(Transient):每次请求服务时都会提供一个新的实例。
    • 作用域(Scoped):在一个作用域内提供单个实例。在Web应用程序中,一个作用域通常对应单个HTTP请求。
    • 单例(Singleton):在应用程序的整个生命周期内只提供一个实例。
  • 服务注册:服务是在Startup类的ConfigureServices方法中向依赖注入容器进行注册的。注册时需指定服务类型、实现类型以及服务生命周期。

基本用法

  • 服务注册: 在Startup类中,你可以在ConfigureServices方法里注册服务,如下所示:
代码语言:javascript
代码运行次数:0
复制
public classStartup
{
    publicvoidConfigureServices(IServiceCollection services)
    {
        services.AddTransient<IMyTransientService, MyTransientService>();
        services.AddScoped<IMyScopedService, MyScopedService>();
        services.AddSingleton<IMySingletonService, MySingletonService>();
    }

    publicvoidConfigure(IApplicationBuilder app,IWebHostEnvironment env)
    {
        // 配置逻辑...
    }
}
  • 服务使用: 服务可以通过构造函数注入的方式注入到各类类中,比如控制器,示例如下:
代码语言:javascript
代码运行次数:0
复制
public classMyController:Controller
{
    privatereadonlyIMyTransientService _transientService;
    privatereadonlyIMyScopedService _scopedService;
    privatereadonlyIMySingletonService _singletonService;

    publicMyController(IMyTransientService transientService,IMyScopedService scopedService,IMySingletonService singletonService)
    {
        _transientService = transientService;
        _scopedService = scopedService;
        _singletonService = singletonService;
    }

    publicIActionResultIndex()
    {
        // 使用服务...
        returnView();
    }
}

高级用法

  • 直接使用IServiceProvider: 虽然构造函数注入是首选的方式,但在某些情况下,你可能需要手动解析服务。可以通过注入IServiceProvider来实现,示例如下:
代码语言:javascript
代码运行次数:0
复制
public classMyService
{
    privatereadonlyIServiceProvider _serviceProvider;

    publicMyService(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    publicvoidDoSomething()
    {
        var transientService = _serviceProvider.GetService<IMyTransientService>();
        transientService.PerformTask();
    }
}
  • 创建作用域: 在某些情况下,你可能需要手动创建一个作用域。这在后台服务或其他非Web环境中很常见,示例如下:
代码语言:javascript
代码运行次数:0
复制
public classMyBackgroundService:BackgroundService
{
    privatereadonlyIServiceProvider _serviceProvider;

    publicMyBackgroundService(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    protectedoverrideasyncTaskExecuteAsync(CancellationToken stoppingToken)
    {
        using(var scope = _serviceProvider.CreateScope())
        {
            var scopedService = scope.ServiceProvider.GetService<IMyScopedService>();
            await scopedService.DoWork(stoppingToken);
        }
    }
}
  • 使用IServiceScopeFactory: 当当前上下文没有提供作用域时,IServiceScopeFactory可用于手动创建作用域,示例如下:
代码语言:javascript
代码运行次数:0
复制
public classMyService
{
    privatereadonlyIServiceScopeFactory _scopeFactory;

    publicMyService(IServiceScopeFactory scopeFactory)
    {
        _scopeFactory = scopeFactory;
    }

    publicvoidDoSomething()
    {
        using(var scope = _scopeFactory.CreateScope())
        {
            var scopedService = scope.ServiceProvider.GetService<IMyScopedService>();
            scopedService.PerformTask();
        }
    }
}
  • 有条件地注册服务: 有时,你可能需要根据特定条件来注册服务,示例如下:
代码语言:javascript
代码运行次数:0
复制
public classStartup
{
    publicvoidConfigureServices(IServiceCollection services)
    {
        if(someCondition)
        {
            services.AddScoped<IMyService, MyServiceImplementation1>();
        }
        else
        {
            services.AddScoped<IMyService, MyServiceImplementation2>();
        }
    }
}

理解服务生命周期

  • 瞬态(Transient): 每次请求服务时都会创建一个新的实例。 适用于轻量级、无状态的服务。 示例:
代码语言:javascript
代码运行次数:0
复制
services.AddTransient<IMyService, MyService>();
  • 作用域(Scoped): 每个请求或作用域内会创建一个新的实例。 适用于在单个请求范围内维护状态,但超出该范围则无需维护状态的服务。 示例:
代码语言:javascript
代码运行次数:0
复制
services.AddScoped<IMyService, MyService>();
  • 单例(Singleton): 创建一个单一实例,并在应用程序的整个生命周期内共享该实例。 适用于在全局范围内维护状态或者创建成本较高的服务。 示例:
代码语言:javascript
代码运行次数:0
复制
services.AddSingleton<IMyService, MyService>();

最佳实践

  • 优先使用构造函数注入:这有助于实现不可变特性,并确保在类实例化时依赖项可用。
  • 避免服务定位器模式:虽然IServiceProvider允许手动解析服务,但过度使用它可能会导致一种称为“服务定位器”的反模式,这种模式会隐藏依赖关系,使代码更难维护。
  • 恰当地使用作用域:确保在作用域内解析作用域服务。避免直接从单例服务中解析作用域服务。
  • 避免依赖项捕获问题:当生命周期较短的服务(例如瞬态或作用域服务)被注入到生命周期较长的服务(例如单例服务)中时,就会出现依赖项捕获问题。这可能会导致意外行为和资源泄漏。

通过理解并遵循这些概念和实践,你可以在.NET Core应用程序中使用IServiceProvider有效地管理依赖关系和服务生命周期。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-01-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 DotNet NB 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 关键概念
  • 基本用法
  • 高级用法
  • 理解服务生命周期
  • 最佳实践
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档