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

Blazor同步模式下获取会话ID的实现方案求助

Blazor (.NET 7) 自定义会话ID实现方案

技术背景

使用.NET 7.0 + Blazor构建Web应用,数据源连接由IMoxClientConnection实例管理,每个用户需对应独立实例(无需每次打开页面重新登录)。已实现ConnectionHandler(基于MoxSessionId与IMoxClientConnection实例的字典)并注册为Singleton服务,所有业务服务通过其GetClientConnectorForSession(string moxSessionId)方法获取对应连接实例。

核心需求

为每个客户端浏览器标签页生成唯一会话ID,标签页打开使用期间保持持久,暂不考虑浏览器/标签页关闭后的留存。

已尝试方案

最初计划通过Cookie存储自定义会话ID,因Blazor中实现复杂度转而尝试ProtectedSessionStorage:

  1. 在Program.cs中注册服务:builder.Services.AddScoped<ProtectedSessionStorage>();
  2. 在基础服务类中编写同步方法获取/生成会话ID:
private string CreateOrGetSessionId()
{
  var sessionId = _sessionStorage.GetAsync<string>("MoxSessionId").Result.Value;

  if (string.IsNullOrWhiteSpace(sessionId))
  {
    sessionId = Guid.NewGuid().ToString();
    _sessionStorage.SetAsync("MoxSessionId", sessionId);
  }

  return sessionId;
}

遇到的问题

执行GetAsync后程序无响应,尝试查找同步方法(如GetItem)也无法正常工作。

可行实现方案

问题根源

Blazor中ProtectedSessionStorage的方法均为异步操作,同步方法中使用.Result会阻塞主线程,而JS互操作(SessionStorage依赖JS)需要主线程资源,最终导致死锁。必须采用异步方式处理。

方案1:基于ProtectedSessionStorage的异步会话管理

1. 创建Scoped会话ID服务

public class SessionIdService
{
    private readonly ProtectedSessionStorage _sessionStorage;
    private string _cachedSessionId;

    public SessionIdService(ProtectedSessionStorage sessionStorage)
    {
        _sessionStorage = sessionStorage;
    }

    public async Task<string> GetSessionIdAsync()
    {
        // 优先使用缓存的会话ID
        if (!string.IsNullOrWhiteSpace(_cachedSessionId))
            return _cachedSessionId;

        // 从SessionStorage读取
        var storageResult = await _sessionStorage.GetAsync<string>("MoxSessionId");
        if (storageResult.Success && !string.IsNullOrWhiteSpace(storageResult.Value))
        {
            _cachedSessionId = storageResult.Value;
            return _cachedSessionId;
        }

        // 生成新会话ID并存储
        _cachedSessionId = Guid.NewGuid().ToString();
        await _sessionStorage.SetAsync("MoxSessionId", _cachedSessionId);
        return _cachedSessionId;
    }
}

2. 注册服务

在Program.cs中添加:

builder.Services.AddScoped<SessionIdService>();

3. 在业务服务中使用

public class YourBusinessService
{
    private readonly SessionIdService _sessionIdService;
    private readonly ConnectionHandler _connectionHandler;

    public YourBusinessService(SessionIdService sessionIdService, ConnectionHandler connectionHandler)
    {
        _sessionIdService = sessionIdService;
        _connectionHandler = connectionHandler;
    }

    public async Task ExecuteDataOperationAsync()
    {
        var sessionId = await _sessionIdService.GetSessionIdAsync();
        var clientConnection = _connectionHandler.GetClientConnectorForSession(sessionId);
        
        // 使用clientConnection执行数据源操作
    }
}

方案2:无需加密,使用普通SessionStorage

若无需会话ID加密保护,可改用ISessionStorageService(Blazor Server需确保启用JS互操作,Blazor WebAssembly需引入Microsoft.AspNetCore.Components.WebAssembly.Storage包):

1. 注册服务

builder.Services.AddScoped<ISessionStorageService, SessionStorageService>();

2. 修改SessionIdService

public class SessionIdService
{
    private readonly ISessionStorageService _sessionStorage;
    private string _cachedSessionId;

    public SessionIdService(ISessionStorageService sessionStorage)
    {
        _sessionStorage = sessionStorage;
    }

    public async Task<string> GetSessionIdAsync()
    {
        if (!string.IsNullOrWhiteSpace(_cachedSessionId))
            return _cachedSessionId;

        _cachedSessionId = await _sessionStorage.GetItemAsync<string>("MoxSessionId");
        if (string.IsNullOrWhiteSpace(_cachedSessionId))
        {
            _cachedSessionId = Guid.NewGuid().ToString();
            await _sessionStorage.SetItemAsync("MoxSessionId", _cachedSessionId);
        }
        return _cachedSessionId;
    }
}

后续使用方式与方案1一致。

内容的提问来源于stack exchange,提问作者Markus H.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 14:53:08