You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Blazor中在组件、路由、页面间共享对象的实现方案

解决方案:用单例服务实现全局共享数据

1. 定义数据模型类

先创建存储文件解析后数据的实体类,根据你的实际数据结构调整:

public class AppDatabase
{
    // 对应文件中的数据库字段,自行扩展
    public string DbName { get; set; }
    public List<DataRecord> Records { get; set; } = new();
}

public class DataRecord
{
    // 数据项的具体字段
    public int Id { get; set; }
    public string Content { get; set; }
}

2. 创建单例服务类

写一个服务类管理全局数据,负责文件解析和数据共享:

public class DatabaseService
{
    // 全局唯一的数据库对象
    public AppDatabase CurrentDb { get; private set; }

    // 加载并解析文件的方法
    public async Task LoadAndParseFile(string filePath)
    {
        // 读取文件内容,这里以文本文件为例,根据你的文件类型调整解析逻辑
        var fileContent = await File.ReadAllTextAsync(filePath);
        
        // 解析内容到CurrentDb,比如用JSON反序列化或自定义解析逻辑
        CurrentDb = JsonSerializer.Deserialize<AppDatabase>(fileContent);
        
        // 触发更新事件,通知所有组件数据变化
        OnDbUpdated?.Invoke();
    }

    // 用于通知组件数据更新的事件
    public event Action OnDbUpdated;
}

3. 注册单例服务

在Program.cs里将服务注册为单例,确保整个应用生命周期只有一个实例:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
// 注册单例服务
builder.Services.AddSingleton<DatabaseService>();

var app = builder.Build();

// ... 其他中间件配置代码

4. 在MainLayout中处理文件选择

利用MainLayout的全局特性,在这里添加文件选择逻辑,调用服务加载数据:

@inject DatabaseService DbService
@implements IDisposable

<NavMenu />

<div class="main">
    <div class="top-row px-4">
        <!-- 文件选择控件 -->
        <input type="file" @onchange="HandleFileSelect" accept=".json,.txt" />
    </div>

    <div class="content px-4">
        @Body
    </div>
</div>

@code {
    protected override void OnInitialized()
    {
        // 订阅数据更新事件,可选
        DbService.OnDbUpdated += UpdateLayoutUI;
    }

    private async Task HandleFileSelect(InputFileChangeEventArgs e)
    {
        if (e.File == null) return;

        // 临时保存文件(Blazor Server端示例,WebAssembly端读取方式略有不同)
        var tempPath = Path.GetTempFileName();
        using var stream = new FileStream(tempPath, FileMode.Create);
        await e.File.OpenReadStream().CopyToAsync(stream);

        // 调用服务解析文件
        await DbService.LoadAndParseFile(tempPath);
    }

    private void UpdateLayoutUI()
    {
        // 刷新布局UI(如果需要)
        StateHasChanged();
    }

    public void Dispose()
    {
        // 取消事件订阅,避免内存泄漏
        DbService.OnDbUpdated -= UpdateLayoutUI;
    }
}

5. 在任意组件中访问和更新数据

直接注入DatabaseService就能获取全局数据,还能响应数据变化:

@inject DatabaseService DbService
@implements IDisposable

<h3>数据库内容展示</h3>

@if (DbService.CurrentDb != null)
{
    <p>数据库名称:@DbService.CurrentDb.DbName</p>
    <ul>
        @foreach (var record in DbService.CurrentDb.Records)
        {
            <li>ID: @record.Id | 内容: @record.Content</li>
        }
    </ul>
    <button @onclick="UpdateDbData">修改数据库名称</button>
}
else
{
    <p>请先选择数据库文件</p>
}

@code {
    protected override void OnInitialized()
    {
        // 订阅数据更新事件,自动刷新UI
        DbService.OnDbUpdated += RefreshComponent;
    }

    private void RefreshComponent()
    {
        StateHasChanged();
    }

    private void UpdateDbData()
    {
        if (DbService.CurrentDb == null) return;
        
        // 直接修改全局数据
        DbService.CurrentDb.DbName = "更新后的数据库名称";
        // 触发事件通知所有组件更新
        DbService.OnDbUpdated?.Invoke();
    }

    public void Dispose()
    {
        DbService.OnDbUpdated -= RefreshComponent;
    }
}

关键说明

  • 不需要通过路由或组件参数传递数据,所有组件通过依赖注入直接获取同一个服务实例,共享CurrentDb对象。
  • 单例服务在应用启动时创建,文件只会被解析一次(除非主动调用LoadAndParseFile重新加载)。
  • 通过服务内的OnDbUpdated事件,能实现跨组件的数据更新通知,确保所有组件UI同步变化。

内容的提问来源于stack exchange,提问作者DaveK

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 12:35:40