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

ASP.NET应用添加带数据库连接的WebSocket遇依赖注入问题

问题分析与解决方案

你的核心问题出在中间件生命周期与Scoped服务的冲突:ASP.NET中间件的构造函数是在应用启动阶段由根服务提供者解析的,而DatabaseService是Scoped生命周期(每个请求创建实例),根提供者无法直接解析Scoped服务;同时手动注册中间件为Scoped时,又无法自动注入RequestDelegate(中间件链的固定参数)。

解决步骤

1. 修改WebSocketMiddleware类

移除构造函数中的DatabaseService注入,改为在请求执行阶段通过HttpContext获取Scoped服务:

public class WebSocketMiddleware
{
    private readonly RequestDelegate next;

    // 仅保留RequestDelegate参数,符合中间件构造规范
    public WebSocketMiddleware(RequestDelegate next)
    {
        this.next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        if (context.WebSockets.IsWebSocketRequest)
        {
            // 从当前请求的服务容器中获取Scoped的DatabaseService
            var databaseService = context.RequestServices.GetRequiredService<DatabaseService>();
            WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync();
            await HandleWebSocketConnection(context, webSocket, databaseService);
        }
        else
        {
            Console.WriteLine("Not ws");
            await next(context);
        }
    }

    // 新增DatabaseService参数,在方法内直接使用
    private async Task HandleWebSocketConnection(HttpContext context, WebSocket webSocket, DatabaseService databaseService)
    {
        // 在这里正常调用databaseService的数据库操作方法
        // 示例:var data = await databaseService.GetRecordsAsync();
        // ... 其他WebSocket消息处理逻辑
    }
}

2. 修正Program.cs中的服务注册

移除手动注册WebSocketMiddleware的代码,因为ASP.NET框架会通过UseMiddleware<T>自动处理中间件的实例化:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

builder.Services.AddDbContext<DatabaseContext>(options =>
    options.UseNpgsql("address"));

builder.Services.AddScoped<DatabaseService>();
// 删除这一行:builder.Services.AddScoped<WebSocketMiddleware>();

builder.Services.AddCors(options =>
{
    options.AddPolicy("AllowLocalhost",
        builder =>
        {
            builder.WithOrigins("https://localhost:3000")
                .AllowAnyHeader()
                .AllowCredentials()
                .AllowAnyMethod();
        });
});

var app = builder.Build();

app.UseCors("AllowLocalhost");

app.UseWebSockets();
app.UseMiddleware<WebSocketMiddleware>(); // 保留该行,框架自动处理中间件构造

app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();

app.Run();

3. 保留DatabaseService的原有实现

你的DatabaseService和DatabaseContext的依赖注入配置是正确的,无需修改:

public class DatabaseService
{
    private readonly DatabaseContext databaseContext;

    public DatabaseService(DatabaseContext databaseContext)
    {
        this.databaseContext = databaseContext;
    }

    // 你的数据库操作方法
}

原理说明

  • 中间件构造函数仅在应用启动时执行一次,属于根生命周期,不能直接依赖Scoped服务;而Invoke方法是每个请求都会执行,通过context.RequestServices可以获取当前请求的Scoped服务实例,完全符合依赖注入的生命周期规则。
  • UseMiddleware<T>会自动处理中间件的实例化,并注入RequestDelegate参数,不需要手动将中间件注册到DI容器。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 21:38:12