C# 如何在ASPNET Core 3.0中启动后台进程?
我知道新的ASPNET Core 3.0堆栈在托管进程方面有很多改进 我很好奇从一个模型中定义和执行后台进程的最佳方法是什么?这意味着我有一些逻辑,需要在后台启动一些东西,然后剃须刀页面不需要监控它的结果,但我也希望能够观察它,如果这不是很难的话C# 如何在ASPNET Core 3.0中启动后台进程?,c#,asp.net-core,razor-pages,C#,Asp.net Core,Razor Pages,我知道新的ASPNET Core 3.0堆栈在托管进程方面有很多改进 我很好奇从一个模型中定义和执行后台进程的最佳方法是什么?这意味着我有一些逻辑,需要在后台启动一些东西,然后剃须刀页面不需要监控它的结果,但我也希望能够观察它,如果这不是很难的话 有人能给我看一个代码示例或给我指出正确的方向吗?由于这可能是您的后续工作,我假设您希望在ASP.NET核心应用程序中有一些能够执行后台任务的后台服务(作为托管服务)。现在您想通过控制器或Razor页面操作触发这样的任务,并在后台执行它吗 一种常见的模式
有人能给我看一个代码示例或给我指出正确的方向吗?由于这可能是您的后续工作,我假设您希望在ASP.NET核心应用程序中有一些能够执行后台任务的后台服务(作为托管服务)。现在您想通过控制器或Razor页面操作触发这样的任务,并在后台执行它吗 一种常见的模式是使用一些中央存储来跟踪后台服务和web应用程序都可以访问的任务。实现这一点的一个简单方法是使其成为双方都可以访问的(线程安全的)单例服务 这些文档实际上展示了一个使用
BackgroundTaskQueue
的简单示例,它正是共享服务/状态。但是,如果您有一名工人从事特定类型的工作,您也可以这样实施:
public class JobQueue<T>
{
private readonly ConcurrentQueue<T> _jobs = new ConcurrentQueue<T>();
private readonly SemaphoreSlim _signal = new SemaphoreSlim(0);
public void Enqueue(T job)
{
_jobs.Enqueue(job);
_signal.Release();
}
public async Task<T> DequeueAsync(CancellationToken cancellationToken = default)
{
await _signal.WaitAsync(cancellationToken);
_jobs.TryDequeue(out var job);
return job;
}
}
public class MyJobBackgroundService : BackgroundService
{
private readonly ILogger<MyJobBackgroundService> _logger;
private readonly JobQueue<MyJob> _queue;
public MyJobBackgroundService(ILogger<MyJobBackgroundService> logger, JobQueue<MyJob> queue)
{
_logger = logger;
_queue = queue;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
var job = await _queue.DequeueAsync(stoppingToken);
// do stuff
_logger.LogInformation("Working on job {JobId}", job.Id);
await Task.Delay(2000);
}
}
}
公共类作业队列
{
私有只读ConcurrentQueue_作业=新建ConcurrentQueue();
私有只读信号量lim _signal=新信号量lim(0);
公共无效排队(T作业)
{
_作业。排队(作业);
_信号。释放();
}
公共异步任务出列异步(CancellationToken CancellationToken=default)
{
wait_signal.WaitAsync(cancellationToken);
_jobs.TryDequeue(out-var-job);
返回工作;
}
}
然后,您可以向服务集合以及在此队列上工作的托管后台服务注册此服务的实现:
services.AddSingleton<JobQueue<MyJob>>();
services.AddHostedService<MyJobBackgroundService>();
services.AddSingleton();
services.AddHostedService();
该托管服务的实现可能如下所示:
public class JobQueue<T>
{
private readonly ConcurrentQueue<T> _jobs = new ConcurrentQueue<T>();
private readonly SemaphoreSlim _signal = new SemaphoreSlim(0);
public void Enqueue(T job)
{
_jobs.Enqueue(job);
_signal.Release();
}
public async Task<T> DequeueAsync(CancellationToken cancellationToken = default)
{
await _signal.WaitAsync(cancellationToken);
_jobs.TryDequeue(out var job);
return job;
}
}
public class MyJobBackgroundService : BackgroundService
{
private readonly ILogger<MyJobBackgroundService> _logger;
private readonly JobQueue<MyJob> _queue;
public MyJobBackgroundService(ILogger<MyJobBackgroundService> logger, JobQueue<MyJob> queue)
{
_logger = logger;
_queue = queue;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
var job = await _queue.DequeueAsync(stoppingToken);
// do stuff
_logger.LogInformation("Working on job {JobId}", job.Id);
await Task.Delay(2000);
}
}
}
公共类MyJobBackgroundService:BackgroundService
{
专用只读ILogger\u记录器;
私有只读作业队列_队列;
公共MyJobBackgroundService(ILogger记录器、作业队列)
{
_记录器=记录器;
_队列=队列;
}
受保护的覆盖异步任务ExecuteAsync(CancellationToken stoppingToken)
{
同时(!stoppingToken.IsCancellationRequested)
{
var job=wait _queue.DequeueAsync(stoppingToken);
//做事
_logger.LogInformation(“处理作业{JobId}”,job.Id);
等待任务。延迟(2000);
}
}
}
在控制器操作或Razor页面模型中,您只需插入JobQueue
,然后在其上调用Enqueue
,将作业添加到列表中。一旦后台服务准备好处理它,它就会处理它
最后请注意,队列显然位于内存中,因此,如果应用程序关闭,则尚未执行的作业列表也将消失。如果需要,您当然也可以将这些信息保存在数据库中,并从数据库中设置队列。AJAX就是其中一种方法。绞刑是另一种情况。他们有点不同。我建议你研究这两个问题,尝试一些事情,然后回复一个特定的问题。