为了账号安全,请及时绑定邮箱和手机立即绑定

ASP.NET Core 中的服务生命周期详解(包含键值服务)

标签:
C# .NET

ASP.NET Core 提供了可以在代码中进行依赖注入的服务生命周期选项。

遵循SOLID原则中的“D”原则,即“高层模块不应依赖于低层模块,它们应该依赖于抽象”。ASP.NET Core 通过构造函数大量使用依赖注入,并且提供了服务的生命周期 — 范围、瞬时和单例。

服务生命周期的目标是在我们的应用程序中注入不同的服务,并确定这些服务是如何被创建和复用的,以及它们的复用方式。

在 .NET Core 中有四种服务生命周期类型。

单例服务的生命周期

这种单例生命周期确保对象只会被创建一次,并在管道中反复使用。所以无论你怎样或多少次调用这个对象,一旦实例化,它的值将一直保持不变,直到主机重启。单例生命周期最适合用于无状态的对象,比如“日志”记录。

这些就像是这样的全局变量。

让我们以一个叫做 ClientId 的东西为例,它只是返回一个 Guid 值。


    public class 客户端ID  
    {  
        public Guid Id;  
        public 客户端ID()  
        {  
            Id = Guid.NewGuid();  
        }  

        public Guid 显示GUID()  
        {  
            return Id;  
        }  
    }

这个类在构造函数中分配并初始化一个 Guid,并定义了一个输出 Guid 值的方法。在服务集合中,此类被注入为单例服务。

    services.AddSingleton<ClientId>(); // 这行代码为服务添加了一个单例ClientId对象
using Microsoft.AspNetCore.Mvc;  // 使用 Microsoft.AspNetCore.Mvc;

namespace Lifetime.Controller;  // 命名空间 Lifetime.Controller;

[ApiController]  // API控制器特性
[Route("api/")]  // 路由
public class LifetimeController : ControllerBase  // 公共类 LifetimeController 继承自 ControllerBase
{
    ClientId clientId;  // 客户端ID
    public LifetimeController(ClientId clientId)  // 构造函数
    {
        this.clientId = clientId;  // 初始化客户端ID
    }
    [HttpGet("lifetime")]  // GET请求
    public IActionResult Get()  // 获取方法
    {
        return Ok(clientId.ShowGuid());  // 返回客户端ID的GUID
    }

}

无论 Singleton() 端点被调用多少次,它都会返回同一个 Guid,直到主机重启。

作用域服务生命周期

作用域服务的生命周期每个请求只创建一次,并在请求处理管道中使用

如果实例在构造函数中多次初始化,整个请求过程中都会使用同一个实例。

使用之前的代码,如果我们把 ServiceCollection 中的服务生命周期改为 Scoped 服务,你就会看到 Guid 的值每次都不同。而在控制器中,如果我们每次在构造函数中解析 ClientId 两次并运行代码,你就会看到每次请求时 ClientId 使用的是同一个实例,也就是说。

    services.AddScoped<ClientId>();

以下是代码片段的解释:
这段代码将 ClientId 注册为一个单例服务。

using Microsoft.AspNetCore.Mvc;  // 使用Microsoft ASP.NET Core MVC库

namespace Lifetime.Controller;  // 命名空间Lifetime.Controller

[ApiController]  // 标记为API控制器
[Route("api/")]  // 路由到/api/
public class LifetimeController : ControllerBase  // 定义LifetimeController类继承自ControllerBase
{  
    ClientId clientId;  // 客户端ID1
    ClientId clientId2;  // 客户端ID2
    public LifetimeController(ClientId clientId, ClientId clientId2)  // 构造函数
    {  
        this.clientId = clientId;  // 初始化clientId
        this.clientId2 = clientId2;  // 初始化clientId2
    }  
    [HttpGet("lifetime")]  // 标记为GET请求,路由到/lifetime
    public IActionResult Get()  // 定义Get方法
    {  
        // 返回一个包含两个客户端ID的OK响应
        return Ok(new{id1 = clientId.ShowGuid(), id2=clientId2.ShowGuid()});
    }  
}

在实体框架中最适合使用范围服务的地方是,在那里我们可以只实例化一次DbContext和泛型仓储对象,并在整个请求过程中复用它们。我们不想在每次请求时都创建新的实例。

    service.AddDbContext<BelemaContext>(options =>  
    {  
        options.UseNpgsql(configuration["ConnectionString"], opt =>  
        {  
            opt.EnableRetryOnFailure(15, TimeSpan.FromSeconds(30), errorCodesToAdd: null);  // 启用重试失败功能,最多重试15次,每次重试间隔30秒  
        });  
    });

默认作用域

暂时服务生命周期

每次请求都会创建一个新的瞬时服务。如果我们运行上述代码,并将服务生命周期更改为瞬时,你会发现这些值每次都不同,因为它们每次请求都会被创建。它们最适合用于轻量级无状态服务。

    services.AddTransient<ClientId>();
using Microsoft.AspNetCore.Mvc;  

namespace Lifetime.Controllers;  

[ApiController]  
[Route("api/")]  
public class LifetimeController : ControllerBase  
{  
    ClientId clientId;  
    ClientId clientId2;  
    /// <summary>  
    /// 构造函数,初始化两个客户端ID  
    /// </summary>  
    /// <param name="clientId">第一个客户端ID</param>  
    /// <param name="clientId2">第二个客户端ID</param>  
    public LifetimeController(ClientId clientId, ClientId clientId2)  
    {  
        this.clientId = clientId;  
        this.clientId2 = clientId2;        
    }  
    [HttpGet("lifetime")]  
    public IActionResult Get()  
    {  
        // 返回包含两个客户端ID的响应  
        return Ok(new { id1 = clientId.ShowGuid(), id2 = clientId2.ShowGuid() });  
    }  
}  
键控服务

ASP.NET Core 8 引入了一种新的服务生命周期,称为 KeyedServices。KeyedServices 通过分配键来管理不同服务生命周期的机制。有三种键服务,分别是:

  • 添加带有键的scoped服务
  • 添加带有键的单例服务
  • 添加带有键的暂时服务

它是这样运作的:

    services.AddKeyedSingleton<ClientId>("key1"); //key1 是一个键,表示特定的服务实例
    using Microsoft.AspNetCore.Mvc;  

    命名空间 Lifetime.Controllers;  

    [ApiController]  
    [Route("api/")]  
    public class LifetimeController : ControllerBase  
    {  

        [HttpGet("lifetime")]  
        public IActionResult Get([FromKeyedServices("key1")] ClientId client)  
        {  
            return Ok(client.ShowGuid());  
        }  

    }

为进一步提升您的ASP.NET Core技能,您可以注册此课程Udemy,该课程从基础知识开始,并提供源代码。

也可以看看我关于如何从头开始构建领域驱动设计(DDD)项目的这篇介绍文章。

如果你想学习一个强大的前端框架,可以看看涵盖了TypeScript、React和Next.js的入门课程。该课程还包括一个用.NET开发的后端,进一步提高你的软件开发技能。

编程愉快!

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消