问题
I know that the new ASPNET Core 3.0 stack has a number of improvements around hosting processes.
I am curious about the best way to be able to define and execute a background process from a Razor PageModel? Meaning I have some logic that needs to start something in the background and then that Razor page doesn't need to monitor it's outcome, but I would like to be able to observe it too if that's not too hard.
Can someone show me a code sample or point me in the right direction?
回答1:
Since this is probably a follow-up from your previous question about IHostedService, I am going to assume that you want to have some background service (as a hosted service) within your ASP.NET Core application that is able to perform background tasks. And now you want to trigger such a task through a controller or Razor page action and have it executed in the background?
A common pattern for this is to have some central storage that keeps track of the tasks which both the background service and the web application can access. A simple way to do this is to make it a (thread-safe) singleton service that both sides can access.
The docs actually show a simple example using a BackgroundTaskQueue
which is exactly that shared service/state. If you have a worker for a specific kind of job though, you could also implement it like this:
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;
}
}
You can then register an implementation of this with the service collection along with a hosted background service that works on this queue:
services.AddSingleton<JobQueue<MyJob>>();
services.AddHostedService<MyJobBackgroundService>();
The implementation of that hosted service could then look like this:
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);
}
}
}
In a controller action or a Razor page model, you then just need to inject the JobQueue<MyJob>
and then call Enqueue
on it to add a job to the list. Once the background service is ready to process it, it will then work on it.
Finally note that the queue is obviously in-memory, so if your application shuts down, the list of yet-to-do jobs is also gone. If you need, you could also persist this information within a database of course and set up the queue from the database.
来源:https://stackoverflow.com/questions/60244633/how-do-you-launch-a-background-process-in-aspnet-core-3-0