在 Blazor 和 ASP.NET Core 中使用依赖注入和Scoped 服务实现数据共享方法详解

依赖注入(Dependency Injection,简称 DI)是一种设计模式,用于将对象的依赖关系从对象内部解耦出来,由外部容器进行管理和提供。在 Blazor 和 ASP.NET Core 中,DI 是内置的核心功能,它通过服务生命周期(Transient、Scoped、Singleton)来管理依赖项。


依赖注入(Dependency Injection)详解

核心概念

  1. 服务(Service):

    • 服务是一个类,封装了某些功能,可以被应用程序的其他部分使用。
  2. 服务容器(Service Container):

    • DI 容器是一个管理服务实例的工具,负责创建和提供服务实例。
    • ASP.NET Core 和 Blazor 中,IServiceCollection 是服务容器的接口,配置服务时通过它进行注册。
  3. 依赖关系:

    • 一个类如果需要另一个类来完成其功能,这种关系称为依赖关系。

DI 的优点

  • 解耦: 提高代码的模块化和可维护性。
  • 测试性: 通过注入模拟对象(mock)可以轻松测试。
  • 生命周期管理: DI 容器负责服务的创建、销毁和共享。

服务的生命周期

在 Blazor 和 ASP.NET Core 中,DI 服务的生命周期有三种:

  1. Transient(瞬态):

    • 每次请求都会创建一个新的实例。

    • 适合轻量级、无状态的服务。

      builder.Services.AddTransient<IMyService, MyService>();

  2. Scoped(作用域):

    • 在 Blazor Server 中,每个用户会话(或 SignalR 连接)会创建一个实例,并在整个会话中共享。

    • 在 Blazor WebAssembly 中,每个浏览器实例创建一个实例。

    • 适合与特定会话相关的服务。

      builder.Services.AddScoped<IMyService, MyService>();

  3. Singleton(单例):

    • 应用程序的整个生命周期中只有一个实例。

    • 适合全局共享的服务。

      builder.Services.AddSingleton<IMyService, MyService>();


Scoped 服务详解

Scoped 服务的行为

  1. Blazor Server:

    • 每个用户连接(SignalR 会话)有一个独立的实例。
    • 同一个用户的多个标签页共享同一个实例。
  2. Blazor WebAssembly:

    • 每个浏览器实例都有独立的 Scoped 服务实例。
    • 每个标签页有独立的实例。

实现 Scoped 服务

创建 Scoped 服务
  1. 创建一个服务类:

    复制代码
    public class UserInfoService 
    { 
         public string UserName { get; set; } 
         public string Role { get; set; } 
    } 
  2. Program.cs 中注册服务:

    复制代码
    builder.Services.AddScoped<UserInfoService>(); 
使用 Scoped 服务

在页面或组件中注入服务:

复制代码
@inject UserInfoService UserInfoService 
<p>当前用户: @UserInfoService.UserName</p> 

在组件的代码部分更新或读取服务状态:

复制代码
<button @onclick="SetUserInfo">设置用户信息</button> 

@code 
{ 
    private void SetUserInfo() 
       { 
            UserInfoService.UserName = "John Doe"; 
            UserInfoService.Role = "Admin"; 
       } 
} 

Scoped 服务的作用与场景

  1. 用户会话管理:

    • 保存用户的基本信息(用户名、角色等)。
    • 保存会话中需要共享的临时数据。
  2. 中间状态存储:

    • 用于在多步操作中保存状态(如分步骤表单)。
  3. 与数据库或外部服务交互:

    • 每个用户操作的独立上下文(如数据库上下文 DbContext)。

Scoped 服务的注意事项

  1. 线程安全:

    • 在 Blazor Server 中,多个组件可能同时访问 Scoped 服务,确保使用线程安全的方式处理数据。
  2. 避免与 Singleton 服务共享数据:

    • 如果需要共享 Scoped 服务与 Singleton 服务的数据,需特别小心数据一致性问题。
  3. Blazor Server 中多标签页问题:

    • 同一个用户的多个标签页共享 Scoped 服务实例。如果需要为每个标签页提供独立的状态,可以结合 Circuit 或切换为 Transient 服务。

Scoped 服务与其他生命周期的对比

生命周期 实例数 适用场景
Transient 每次请求创建新实例 无状态或轻量级的短期操作服务
Scoped 每个用户会话或浏览器实例一个 用户会话、临时状态
Singleton 整个应用程序一个实例 全局共享服务(如配置或缓存服务)

总结

  • Scoped 服务非常适合在 Blazor 中管理与用户会话相关的数据和状态。
  • 在 Blazor Server 中需要注意多标签页共享的问题;在 Blazor WebAssembly 中无需担心。
  • 使用 Scoped 服务时,保持线程安全是关键,尤其在 Blazor Server 环境下。

根据实际需求选择合适的服务生命周期,以实现高效、可靠的应用设计。

相关推荐
1点东西5 分钟前
新来的同事问我当进程/机器突然停止时,finally 到底会不会执行?
java·后端·程序员
萧戈16 分钟前
如何为 Visual Studio 2019 安装 WDK
ide·visual studio
用户33790448021719 分钟前
HTML5语义化标签详解
前端
唐某人丶22 分钟前
教你如何用 JS 实现一个 Agent 系统(1)—— 认识 Agentic System
前端·人工智能
AAA修煤气灶刘哥24 分钟前
后端仔狂喜!手把手教你用 Java 拿捏华为云 IoTDA,设备上报数据 so easy
后端·物联网·华为
丘山子27 分钟前
分享链接格式不统一,rel="share-url" 提案试图解决这个问题
前端·面试·html
G探险者36 分钟前
如何在批量创建 `DefaultMessageListenerContainer` 时避免阻塞问题
后端
创可贴治愈心灵44 分钟前
WPF中UI线程频繁操作造成卡顿的处理
ui·c#·wpf
我崽不熬夜1 小时前
List、Set、Map,你真的会选用吗?
java·后端·java ee
JustHappy1 小时前
「Versakit攻略」🔥Pnpm+Monorepo+Changesets搭建通用组件库项目和发包流程
前端·javascript·vue.js