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

.NET Core中BackgroundService如何传递用户信息至服务层?

问题描述

我在.NET Core Web应用中通过以下方式将用户信息传递到服务层:

services.AddScoped<RequestInfo>(provider =>
{
    var context = provider.GetRequiredService<IHttpContextAccessor>();

    var userJson = ((ClaimsIdentity)context.HttpContext.User.Identity).FindFirst("LoggedInUser").Value;
    var user = JsonConvert.DeserializeObject<User>(userJson);

    return new RequestInfo(int.Parse(user.UserId), user.ClientId);
});

这个方案在控制器和服务中能正常工作,但我还有一个处理消息的BackgroundService,希望在解析服务处理消息前,把消息中的用户信息传入。请问是否可以实现?或者有什么替代方案?我预想的伪代码如下:

using var scope = serviceProvider.CreateScope();

SetupUserInfo(..have no access to ServiceCollection .., contract user info);

var service = scope.ServiceProvider.GetRequiredService(..my type);

更新:我的初步思路

services.AddScoped<RequestInfo>();

var info = provider.GetRequiredService<RequestInfo>();

info.UserId = .. get info from http context somewhere in middleware (for API)
info.UserId = .. get info from message before resolve of main dependency (for Background service)

解决方案

1. 重构RequestInfo设计

先把RequestInfo调整为可动态赋值的结构(如果之前是只读构造注入的话),适配不同场景的赋值需求:

public class RequestInfo
{
    public int UserId { get; set; }
    public string ClientId { get; set; }
}

然后在DI容器中注册为Scoped生命周期:

services.AddScoped<RequestInfo>();

2. API请求场景:中间件赋值

通过自定义中间件从HttpContext提取用户信息,直接注入当前作用域的RequestInfo:

public class RequestInfoMiddleware
{
    private readonly RequestDelegate _next;

    public RequestInfoMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task InvokeAsync(HttpContext context, RequestInfo requestInfo)
    {
        var userJson = ((ClaimsIdentity)context.User.Identity).FindFirst("LoggedInUser")?.Value;
        if (!string.IsNullOrEmpty(userJson))
        {
            var user = JsonConvert.DeserializeObject<User>(userJson);
            requestInfo.UserId = int.Parse(user.UserId);
            requestInfo.ClientId = user.ClientId;
        }

        await _next(context);
    }
}

// 在Program.cs中注册中间件(注意放在认证中间件之后)
app.UseMiddleware<RequestInfoMiddleware>();

3. BackgroundService场景:手动赋值

在后台服务处理消息时,创建作用域后先获取RequestInfo,从消息中提取用户信息赋值,再获取业务服务使用:

public class MessageProcessingService : BackgroundService
{
    private readonly IServiceProvider _serviceProvider;

    public MessageProcessingService(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            // 模拟从消息队列获取消息
            var message = await FetchNextMessage(stoppingToken);
            if (message == null) continue;

            using var scope = _serviceProvider.CreateScope();
            var requestInfo = scope.ServiceProvider.GetRequiredService<RequestInfo>();
            
            // 从消息中提取用户信息并赋值
            requestInfo.UserId = int.Parse(message.UserId);
            requestInfo.ClientId = message.ClientId;

            // 此时获取业务服务,依赖的RequestInfo已携带用户信息
            var businessService = scope.ServiceProvider.GetRequiredService<IMyBusinessService>();
            await businessService.ProcessMessage(message, stoppingToken);
        }
    }

    private async Task<Message> FetchNextMessage(CancellationToken stoppingToken)
    {
        // 替换为实际的消息队列消费逻辑
        await Task.Delay(1000, stoppingToken);
        return new Message { UserId = "123", ClientId = "Client_001" };
    }
}

4. 可选优化:确保RequestInfo的完整性

如果需要避免RequestInfo未被正确赋值的情况,可以给它添加初始化校验:

public class RequestInfo
{
    private bool _isInitialized;
    public int UserId { get; private set; }
    public string ClientId { get; private set; }

    public void Initialize(int userId, string clientId)
    {
        if (_isInitialized)
            throw new InvalidOperationException("RequestInfo已完成初始化,不可重复赋值");
        
        UserId = userId;
        ClientId = clientId;
        _isInitialized = true;
    }
}

这样在赋值时调用Initialize方法,既能防止重复赋值,也能在业务逻辑中检查_isInitialized状态,避免使用未初始化的用户信息。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 02:15:43