I've followed the getting started tutorial and currently have a TODO CRUD app.
https://docs.microsoft.com/en-us/aspnet/core/tutorials/first-web-api-mac?view=aspnetcore-2.1
I want to add a background worker that updates the todo database every 5 minutes and sets Item 1 to a random value for its Name, and isCompleted properties.
This is pretty easy in Java SpringBoot or Elixir's Phoenix... Is there a quick and painless way in c# to do this?
The doc I found on Microsoft website was from 2012... so I assume there is a more elegant way to do this by now.
Edit: I went with DNTScheduler.Core and it was relatively painless to set up. Followed the exampleApp setup that was on github repo and here is the task i ended up using:
using System;
using System.Threading.Tasks;
using DNTScheduler.Core.Contracts;
using Microsoft.Extensions.Logging;
using myapp.Models;
namespace MyApp.Tasks
{
public class TaskOne : IScheduledTask
{
private readonly ILogger<DoBackupTask> _logger;
private readonly TodoContext _context; // autoinjects since it was added in startup.cs in configure()
public TaskOne(ILogger<DoBackupTask> logger, TodoContext context)
{
_logger = logger;
_context = context;
}
public Task RunAsync()
{
var todo = _context.TodoItems.Find(1);
if (todo == null)
{
return Task.CompletedTask;
}
string[] names = new string[] { "val1", "val2"};
Random r = new Random();
string random_name = names[r.Next(0, names.Length)];
todo.Name = random_name;
_context.TodoItems.Update(todo);
_context.SaveChanges();
_logger.LogInformation("Ran My Task\n\n ");
return Task.CompletedTask;
}
}
}
I would suggest you use Scheduler, there are some packages that can do that, but the best package that I have seen so far is DNTScheduler.Core
DNTScheduler.Core is a lightweight ASP.NET Core's background tasks runner and scheduler.
for more information, you can visit this link
I would argue that the correct answer is wrong if you want to follow the native practice.
Make use of IHostedService to perform repetitive actions.
Here's an answer I've written that addresses that.
There is a saying i've read somewhere: "If its worth doing, its worth doing right. If its not worth doing right - find something that is."
So, as other colleagues already said, web application is not meant to be a container for background processes for reasons already mentioned.
Depending on your environment, you'll be much better off using:
pretty much anything else is looking for trouble when you don't need one.
In this sample I Insert a record to my database ( Word-Suggestion-Table in here) every hour using UnitOfWork
and Repository Pattern
. No error on Cannot consume scoped service *IUnitOfWork* from singleton
1- Add work
class and IWork
interface as below:
using System.Threading;
using System.Threading.Tasks;
namespace Map118.App.BackgroundTasks
{
public interface IWorker
{
Task DoWork(CancellationToken cancellationToken);
}
}
Work.cs :
using Map118.DataLayer.IRepositories;
using Map118.Models;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Map118.App.BackgroundTasks
{
public class Worker : IWorker
{
private readonly IServiceProvider serviceProvider;
public Worker( IServiceProvider serviceProvider)
{
this.serviceProvider = serviceProvider;
}
public async Task DoWork(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
using (var scope = serviceProvider.CreateScope())
{
var _unitOfWork = scope.ServiceProvider.GetRequiredService<IUnitOfWork>();
while (!stoppingToken.IsCancellationRequested)
{
WordSuggestion wordSuggestion = new WordSuggestion()
{
word = Guid.NewGuid().ToString(),
};
await _unitOfWork.wordSuggestionRepository.Add(wordSuggestion);
await _unitOfWork.Save();
await Task.Delay(1000 * 3600);
}
}
}
}
}
}
2- Add another class as below:
using Microsoft.Extensions.Hosting;
using System.Threading;
using System.Threading.Tasks;
namespace Map118.App.BackgroundTasks
{
public class UserActivitiesCleaner : BackgroundService
{
private readonly IWorker worker;
public UserActivitiesCleaner(IWorker worker)
{
this.worker = worker;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
await worker.DoWork(stoppingToken);
}
}
}
3- Add services
to Startup.cs
:
services.AddHostedService<UserActivitiesCleaner>();
services.AddSingleton<IWorker, Worker>();
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.