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

如何通过SignalR获取Controller调用Background Service后的延迟响应?

.NET5 后台服务完成后通过SignalR推送数据实现方案

实现步骤

1. 定义并注册SignalR Hub

首先创建专用的对比结果推送Hub,无需编写业务方法,仅做事件推送的载体即可:

public class CompareResultHub : Hub
{
    // 客户端只需连接该Hub,监听receiveUpdatedText事件即可
}

在Startup.cs中注册SignalR服务和端点:

public void ConfigureServices(IServiceCollection services)
{
    // 原有服务注册保留,新增以下内容
    services.AddSignalR();
    services.AddHttpContextAccessor(); // 后续用于获取当前请求用户ID
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    // 原有中间件配置保留,在端点映射部分新增
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapHub<CompareResultHub>("/compareResultHub");
        // 原有Controller等端点保留
    });
}

2. 修改传输Dto,携带请求用户标识

后台服务需要知道要把结果推给哪个用户,所以需要给VersionDto新增UserId属性:

public class VersionDto
{
    // 原有InitialDraftId、DraftId等属性保留
    public string UserId { get; set; }

    public VersionDto(Guid initialDraftId, Guid draftId, int currVer, int prevVer, string userId)
    {
        // 原有属性赋值保留
        UserId = userId;
    }
}

修改GetComparedTextHandler,注入IHttpContextAccessor获取当前请求的用户ID,构造VersionDto时传入:

public class GetComparedTextHandler : IRequestHandler<GetComparedTextQuery, ComparedDraftDto>
{
    private readonly AppDbContext _appDbContext;
    private readonly TpaChannel _tpaChannel;
    private readonly IHttpContextAccessor _httpContextAccessor;

    public GetComparedTextHandler(AppDbContext appDbContext, TpaChannel tpaChannel, IHttpContextAccessor httpContextAccessor)
    {
        _appDbContext = appDbContext;
        _tpaChannel = tpaChannel;
        _httpContextAccessor = httpContextAccessor;
    }

    public async Task<ComparedDraftDto> Handle(GetComparedTextQuery request, CancellationToken cancellationToken)
    {
        // 原有逻辑保留
        var edDraftComparison = ...;
        if (edDraftComparison == null) 
        {
            // 原有入库、创建Channel逻辑保留
            // 获取当前请求用户ID
            var userId = _httpContextAccessor.HttpContext?.User.FindFirstValue(ClaimTypes.NameIdentifier);
            // 构造VersionDto时传入用户ID
            var versionDto = new VersionDto(request.InitialDraftId, request.DraftId, request.CurrVer, request.PrevVer, userId);
            await _tpaChannel.AddVersionsAsync(versionDto, cts.Token);
        }
        // 原有返回逻辑保留
    }
}

3. 后台服务注入IHubContext,任务完成后推送数据

直接在你处理Channel任务的BackgroundService中注入IHubContext<CompareResultHub>,待仓库记录更新完成后调用推送方法即可:

public class TpaBackgroundService : BackgroundService
{
    private readonly TpaChannel _tpaChannel;
    private readonly AppDbContext _appDbContext;
    private readonly IHubContext<CompareResultHub> _hubContext;

    public TpaBackgroundService(TpaChannel tpaChannel, AppDbContext appDbContext, IHubContext<CompareResultHub> hubContext)
    {
        _tpaChannel = tpaChannel;
        _appDbContext = appDbContext;
        _hubContext = hubContext;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        // 原有读取Channel任务的逻辑保留
        await foreach (var versionDto in _tpaChannel.ReadAllAsync(stoppingToken))
        {
            // 原有更新仓库记录的逻辑执行完成后,新增推送逻辑
            if (!string.IsNullOrEmpty(versionDto.UserId))
            {
                await _hubContext.Clients.User(versionDto.UserId).SendAsync(
                    "receiveUpdatedText",
                    new 
                    {
                        DraftId = versionDto.DraftId,
                        // 填充你需要返回的最新对比结果字段
                    },
                    stoppingToken
                );
            }
        }
    }
}

补充说明

  • 若你使用自定义的用户身份体系,也可以将用户标识替换为SignalR连接ID,需要客户端连接Hub时上报用户ID,在Hub中维护用户ID和连接ID的映射关系,后台服务通过Clients.Client(connectionId)推送即可。
  • React客户端只需正常连接/compareResultHub端点,监听receiveUpdatedText事件即可拿到更新后的对比数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 14:54:04