我有一个同步控制器方法
public IActionResult Action(int num)
{
//operations-1
Task.Run(() => DoWork(num));
//operations-2
int a = num + 123;
return Ok(a);
}和DoWork方法
private bool DoWork(int num)
{
//operations
return true;
}我尝试做的是在从Postman调用端点时在后台运行DoWork方法,但我想在Postman中获得结果,然后调试DoWork方法(从DoWork方法中的断点)-这可能吗?
在那一刻,控制器操作和DoWork()是同时执行的,但是当我到达
return Ok(a);应用程序等待DoWork,而不是返回值。我也试过了
Task.Factory.StartNew(() => DoWork());
ThreadPool.QueueUserWorkItem(o => DoWork());但结果是一样的。
我希望DoWork方法返回值,但控制器操作方法不需要返回值-它将在不同的位置使用,而不是与之连接。
发布于 2018-03-16 18:23:19
Tasks是high level threads,它确保你不会阻塞任何上下文。
您可以使用诸如ASP.NET Core2.0中的RabbitMQ或IHostedService之类的东西来执行在请求完成后触发并忽略的任务。
发布于 2021-08-24 13:21:08
使用后台队列有时有些夸大其词。当您需要访问数据库上下文时,有许多站点向您展示了一种方法。控制器中Task.Run的问题是,衍生的任务不能访问控制器使用的相同上下文,因为它可能(可能会)在该任务访问它之前被处理。您可以通过确保子任务只引用它知道将保持活动状态的依赖项来解决此问题,方法是使用singleton service或更好的数据库上下文,使用IServiceScopeFactory。
关键是要创建一个可以处理数据库上下文或存储库的独立依赖项。这可以像平常一样注入到你的控制器中。
public void Execute(Func<IRepository, Task> databaseWork)
{
// Fire off the task, but don't await the result
Task.Run(async () =>
{
// Exceptions must be caught
try
{
using var scope = _serviceScopeFactory.CreateScope();
var repository = scope.ServiceProvider.GetRequiredService<IRepository>();
await databaseWork(repository);
}
catch (Exception e)
{
Console.WriteLine(e);
}
});
}然后从你的控制器调用它,比如
// Delegate the slow task another task on the threadpool
_fireForgetRepositoryHandler.Execute(async repository =>
{
// Will receive its own scoped repository on the executing task
await repository.DoLOngRunningTaskAsync();;
});发布于 2022-01-11 10:10:38
注意:这是建立在Adem Catamak的答案之上的。
可以使用Hangfire,但不需要实际的数据库,因为它可以与memory storage一起使用
services.AddHangfire(opt => opt.UseMemoryStorage());
JobStorage.Current = new MemoryStorage();虽然它有一些开销,但Hangfire允许管理这些作业,而不是让一些东西异步运行,并需要自定义代码来处理简单的事情,如运行时,未处理的异常,DI支持的自定义代码。
图片来源:Codidact
https://stackoverflow.com/questions/49318224
复制相似问题