C# Worker Service监听端点触发事件并执行指定方法
Worker Service 监听事件实现方案
需求:已通过端点触发事件,需实现Worker Service监听该事件,事件触发时执行对应方法。
当前代码实现
public class WorkerService : BackgroundService { private readonly ILogger<WorkerService> _logger; private readonly IEventService _eventService; public WorkerService(ILogger<WorkerService> logger, IEventService eventService) { _logger = logger; _eventService = eventService; } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { _eventService.RegEvent += Log; await Task.Delay(2000); _eventService.RegEvent -= Log; } private void Log(string message) { _logger.LogInformation("dssd"); } } public interface IEventService { public delegate void RegistrationEvent(string message); public event RegistrationEvent RegEvent; public void InvokeEvent(); } public class EventService : IEventService { private readonly ILogger<EventService> _logger; public event IEventService.RegistrationEvent RegEvent; public EventService(ILogger<EventService> logger) { _logger = logger; } public void InvokeEvent() { RegEvent?.Invoke("Test message"); _logger.LogInformation($"From {nameof(EventService)}"); } }
问题分析
当前代码存在两个核心问题:
- 监听生命周期过短:
ExecuteAsync中订阅事件后仅延迟2秒就取消订阅,Worker Service启动后很快就不再监听事件,无法满足持续监听的需求; - 未利用事件参数:
Log方法硬编码固定字符串,未使用事件传递的message参数。
修正后的实现
1. 调整Worker Service的监听逻辑
确保Worker Service在运行期间始终订阅事件,直到服务停止时才取消订阅:
public class WorkerService : BackgroundService { private readonly ILogger<WorkerService> _logger; private readonly IEventService _eventService; public WorkerService(ILogger<WorkerService> logger, IEventService eventService) { _logger = logger; _eventService = eventService; } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { // 启动时订阅事件 _eventService.RegEvent += Log; _logger.LogInformation("Worker Service 已订阅事件"); try { // 等待服务停止信号,保持服务运行 await Task.Delay(Timeout.Infinite, stoppingToken); } finally { // 服务停止时取消订阅,避免内存泄漏 _eventService.RegEvent -= Log; _logger.LogInformation("Worker Service 已取消事件订阅"); } } private void Log(string message) { // 使用事件传递的消息进行日志记录 _logger.LogInformation("事件触发,消息内容:{Message}", message); } }
2. 添加端点触发示例(API控制器)
用于触发事件的端点实现:
[ApiController] [Route("api/events")] public class EventTriggerController : ControllerBase { private readonly IEventService _eventService; public EventTriggerController(IEventService eventService) { _eventService = eventService; } [HttpPost("trigger")] public IActionResult TriggerEvent() { _eventService.InvokeEvent(); return Ok("事件已触发"); } }
3. 依赖注入配置
在Program.cs中注册服务,注意IEventService需要注册为单例,确保Worker Service和API控制器使用同一个实例传递事件:
var builder = WebApplication.CreateBuilder(args); // 注册事件服务为单例 builder.Services.AddSingleton<IEventService, EventService>(); // 注册Worker Service builder.Services.AddHostedService<WorkerService>(); // 添加控制器服务 builder.Services.AddControllers(); var app = builder.Build(); app.MapControllers(); app.Run();
关键说明
- 生命周期管理:通过
try-finally块确保服务无论正常停止还是异常终止,都会取消事件订阅,避免内存泄漏; - 事件传递可靠性:单例注册
IEventService保证所有组件共享同一个事件实例,触发的事件能被Worker Service接收到; - 业务逻辑对齐:
Log方法使用事件传入的参数,符合事件驱动的业务需求。
内容的提问来源于stack exchange,提问作者Arshaluys
相关产品推荐
相关产品推荐

