ASP.NET Core 6中如何获取Surveyor中间件实例并在控制器中访问
解决控制器无法访问中间件实例的问题
问题根源
- 直接通过
app.UseMiddleware<Surveyor>()注册中间件时,框架仅创建实例用于请求管道,但未将其注册到依赖注入(DI)容器中,因此控制器无法通过构造函数注入获取该实例。 - 即使能注入,当前
BlockedAttacks是实例属性,多请求并发修改时会存在线程安全问题,导致统计数据不准确。
最优解决方案:分离状态到独立服务
将攻击统计状态从中间件中抽离为独立服务,既符合单一职责原则,又能安全地在控制器和中间件之间共享数据。
步骤1:创建攻击统计服务
public class AttackStatistics { private long _blockedAttacks; // 线程安全地读取统计值 public long BlockedAttacks => Interlocked.Read(ref _blockedAttacks); // 线程安全地递增统计值 public void IncrementBlockedAttacks() { Interlocked.Increment(ref _blockedAttacks); } }
步骤2:注册统计服务到DI容器
在Program.cs中添加服务注册:
builder.Services.AddSingleton<AttackStatistics>();
步骤3:修改中间件依赖注入统计服务
更新Surveyor中间件,通过构造函数注入统计服务:
public class Surveyor { private readonly RequestDelegate _next; private readonly AttackStatistics _attackStats; public Surveyor(RequestDelegate next, AttackStatistics attackStats) { _next = next; _attackStats = attackStats; } public async Task InvokeAsync(HttpContext context) { if (context.Request.Headers.TryGetValue("user-agent", out var userAgent) && !string.IsNullOrWhiteSpace(userAgent)) { if (userAgent.ToString().Contains("eye")) { _attackStats.IncrementBlockedAttacks(); context.Response.Redirect("/error"); return; } } await _next(context); } }
步骤4:在控制器中注入统计服务
public class YourController : Controller { private readonly AttackStatistics _attackStats; public YourController(AttackStatistics attackStats) { _attackStats = attackStats; } public IActionResult GetBlockedAttacks() { long count = _attackStats.BlockedAttacks; return Ok($"累计拦截攻击次数:{count}"); } }
步骤5:保持中间件注册不变
Program.cs中的中间件注册无需修改,依然使用:
app.UseMiddleware<Surveyor>();
为什么不推荐直接注入中间件?
直接将中间件注册到DI容器会遇到RequestDelegate无法提供的问题(该类型属于请求管道的一部分,不能直接注册到DI),同时中间件承担状态管理职责会违反单一原则,不利于后续维护和扩展。
内容的提问来源于stack exchange,提问作者Epic Gamer
相关产品推荐
相关产品推荐

