.NET Worker Service通过API端点调用ReadCycle()方法的实现方案
问题描述
我有一个.NET Worker Service,每分钟自动执行一次ReadCycle()方法。现需扩展项目,让该方法也可通过API端点调用。目前API端点已正常运行,但无法在API控制器中关联ReadCycle()方法与响应,请问该如何实现?
原有代码
Worker类代码
private readonly ILogger<Worker> _logger; private readonly IConfiguration Configuration; //Stuff public Worker(ILogger<Worker> logger, IConfiguration configuration) { _logger = logger; Configuration = configuration; } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { while (!stoppingToken.IsCancellationRequested) { ReadCycle(); await Task.Delay(time, stoppingToken); } } public void ReadCycle() { //do Stuff }
API控制器代码
[Route("api/[controller]")] [ApiController] public class Controller:ControllerBase { [HttpPost] public async Task<ActionResult<string>> Post(Model model) { //ReadCycle Call here; Worker.ReadCycle(); //This is obviously not working return CreatedAtAction("POST","Cycle Completed"); } }
Program代码
public static void Main(string[] args) { var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); builder.Services.AddHostedService<Worker>(); var app = builder.Build(); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseHttpsRedirection(); //app.UseAuthorization(); app.MapControllers(); app.Run(); }
解决方案
核心是通过依赖注入让控制器能访问到Worker实例(或解耦后的业务服务),以下是具体实现步骤:
1. 提取业务逻辑接口(推荐)
为降低耦合度,定义一个包含ReadCycle()的接口:
public interface IReadCycleService { void ReadCycle(); }
2. 让Worker实现该接口
修改Worker类,实现IReadCycleService接口,保留原有定时执行逻辑:
public class Worker : BackgroundService, IReadCycleService { private readonly ILogger<Worker> _logger; private readonly IConfiguration _configuration; public Worker(ILogger<Worker> logger, IConfiguration configuration) { _logger = logger; _configuration = configuration; } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { while (!stoppingToken.IsCancellationRequested) { ReadCycle(); await Task.Delay(TimeSpan.FromMinutes(1), stoppingToken); // 替换为你的定时间隔 } } public void ReadCycle() { // 原有业务逻辑 } }
3. 配置依赖注入
在Program.cs中,将Worker同时注册为IHostedService和IReadCycleService,确保控制器能注入到同一个实例:
public static void Main(string[] args) { var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); // 注册单例Worker,同时暴露IReadCycleService接口 var workerDescriptor = ServiceDescriptor.Singleton<IHostedService, Worker>(); builder.Services.Add(workerDescriptor); builder.Services.AddSingleton<IReadCycleService>(provider => (IReadCycleService)provider.GetRequiredService<IHostedService>()); var app = builder.Build(); if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseHttpsRedirection(); app.MapControllers(); app.Run(); }
4. 在控制器中注入并调用
修改控制器,通过构造函数注入IReadCycleService,然后调用方法:
[Route("api/[controller]")] [ApiController] public class CycleController : ControllerBase // 建议使用有意义的控制器名称 { private readonly IReadCycleService _readCycleService; public CycleController(IReadCycleService readCycleService) { _readCycleService = readCycleService; } [HttpPost] public ActionResult<string> Post(Model model) { _readCycleService.ReadCycle(); return CreatedAtAction(nameof(Post), "Cycle Completed"); } }
关键注意事项
- 如果
ReadCycle()是耗时操作,建议改为异步方法Task ReadCycleAsync(),避免阻塞API请求线程 - 并发安全:定时任务和API调用可能同时触发
ReadCycle(),需确保业务逻辑线程安全(比如加锁、使用并发安全容器) - 控制器名称避免使用通用的
Controller,改为业务相关名称(如CycleController),防止路由冲突
内容的提问来源于stack exchange,提问作者Murf
相关产品推荐
相关产品推荐

