gpt4 book ai didi

c# - 从 ASP.NET Core 中的 Controller 操作运行后台任务

转载 作者:可可西里 更新时间:2023-11-01 07:44:01 28 4
gpt4 key购买 nike

我正在使用 C# 和 ASP.NET Core 2.0 开发带有 REST API 的 Web 应用程序。

我想要实现的是,当客户端向端点发送请求时,我将运行一个与客户端请求上下文分离的后台任务,如果任务成功启动,该任务将结束。

我知道有 HostedService 但问题是 HostedService 在服务器启动时启动,据我所知没有办法启动 HostedService 从 Controller 手动。

这是演示问题的简单代码。

[Authorize(AuthenticationSchemes = "UsersScheme")]
public class UsersController : Controller
{
[HttpPost]
public async Task<JsonResult> StartJob([FromForm] string UserId, [FromServices] IBackgroundJobService backgroundService)
{
// check user account
(bool isStarted, string data) result = backgroundService.Start();

return JsonResult(result);
}
}

最佳答案

您仍然可以将 IHostedServiceBlockingCollection 结合使用作为后台任务的基础。

BlockingCollection 创建一个包装器,这样我们就可以将它作为单例注入(inject)。
BlockingCollection.Take 集合为空时不会消耗处理器时间。将取消 token 传递给 .Take 方法将在 token 被取消时正常退出。

public class TasksToRun
{
private readonly BlockingCollection<TaskSettings> _tasks;

public TasksToRun() => _tasks = new BlockingCollection<TaskSettings>(new ConcurrentQueue<TaskSettings>());

public void Enqueue(TaskSettings settings) => _tasks.Add(settings);

public TaskSettings Dequeue(CancellationToken token) => _tasks.Take(token);
}

对于后台进程,我们可以使用 IHostedService 的“内置”实现 - Microsoft.Extensions.Hosting.BackgroundService
该服务将使用从“队列”中提取的任务。

public class TaskProcessor : BackgroundService
{
private readonly TasksToRun _tasks;

public TaskProcessor(TasksToRun tasks) => _tasks = tasks;

protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
await Task.Yield(); // This will prevent background service from blocking start up of application

while (cancellationToken.IsCancellationRequested == false)
{
try
{
var taskToRun = _tasks.Dequeue(_tokenSource.Token);


await ExecuteTask(taskToRun);
}
catch (OperationCanceledException)
{
// execution cancelled
}
catch (Exception e)
{
// Catch and log all exceptions,
// So we can continue processing other tasks
}
}
}
}

然后我们可以从 Controller 添加新任务而不用等待它们完成

public class JobController : Controller
{
private readonly TasksToRun _tasks;

public JobController(TasksToRun tasks) => _tasks = tasks;

public IActionResult PostJob()
{
var settings = CreateTaskSettings();

_tasks.Enqueue(settings);

return Ok();
}
}

用于阻塞收集的包装器应该作为单例注册用于依赖注入(inject)

services.AddSingleton<TasksToRun, TasksToRun>();

注册后台服务

services.AddHostedService<TaskProcessor>();

关于c# - 从 ASP.NET Core 中的 Controller 操作运行后台任务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49813628/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com