Я читал документацию и статьи о HostedServices
в .NET Core и. Но я не понимаю, как его использовать. Моя задача довольно распространенная. У меня есть метод, который будет отправлять Push-уведомления на мобильный телефон (через Google FCM Messaging) каждые 60 секунд. Итак, я хотел бы:
- Запустить его с моего контроллера;
- Остановите его на моем контроллере;
- Показать на представлении отправка продолжается или нет;
- Использовать .NET Core DI.
Я покажу вам мой код.
BackgroundService
public class PushingHostedService : BackgroundService
{
private int _executionCount;
private readonly ILogger<PushingHostedService> _logger;
private readonly int _seconds = 1000 * 10;
private Timer _timer;
// repos
private readonly IPushTemplateRepository _pushTemplateRepository;
private readonly ICustomerEventRepository _customerEventRepository;
private readonly IPushRepository _pushRepository;
private readonly ISenderLogRepository _senderLogRepository;
public readonly IDistributionRepository _distributionRepository;
// services
private readonly IPushTemplateService _pushTemplateService;
private readonly ISendPushService _sendPushService;
public PushingHostedService(ILogger<PushingHostedService> logger, IPushTemplateRepository pushTemplateRepository,
ICustomerEventRepository customerEventRepository, IPushRepository pushRepository,
ISenderLogRepository senderLogRepository, IPushTemplateService pushTemplateService,
ISendPushService sendPushService, IDistributionRepository distributionRepository)
{
_logger = logger;
_pushTemplateRepository = pushTemplateRepository;
_customerEventRepository = customerEventRepository;
_pushRepository = pushRepository;
_senderLogRepository = senderLogRepository;
_pushTemplateService = pushTemplateService;
_sendPushService = sendPushService;
_distributionRepository = distributionRepository;
_executionCount = _senderLogRepository.PushTemplates.Count();
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
_logger.LogDebug($"Sender is started ...");
stoppingToken.Register(() =>
_logger.LogDebug($"Sender is stopping ..."));
while (!stoppingToken.IsCancellationRequested)
{
await Send();
await Task.Delay(_seconds, stoppingToken);
}
_logger.LogDebug($"Sender is stopped ...");
}
public async Task Send() { ... send push via this method }
}
Controller
public class SenderLogController : Controller
{
private readonly ISenderLogRepository _senderLogRepository;
private readonly PushingHostedService _pushingHostedService;
public SenderLogController(ISenderLogRepository senderLogRepository, PushingHostedService pushingHostedService)
{
_senderLogRepository = senderLogRepository;
_pushingHostedService = pushingHostedService;
}
public IActionResult Index(int? pageNumber)
{
var page = pageNumber ?? 1;
var senderLogs = _senderLogRepository.PushTemplates.OrderByDescending(x => x.SenderLogId).ToPagedList(page, 10);
return View(senderLogs);
}
public async Task<IActionResult> StopSender()
{
await _pushingHostedService.StopAsync(CancellationToken.None);
return RedirectToAction("Index");
}
public async Task<IActionResult> StartSender()
{
await _pushingHostedService.StartAsync(CancellationToken.None);
return RedirectToAction("Index");
}
View
<span>
@if (some thing here ...)
{
<strong class="text-success">Pushing is going on!!!</strong>
}
else
{
<strong>Pushing is switched off</strong>
}
</span>
С помощью моего кода я могузапустить и остановить отправку. Но я могу сделать это только один раз.
Может кто-нибудь дать мне понятный пример, как это реализовать? Спасибо!
Обновление
'Как остановить / запустить / проверить, запущена ли фоновая задача HostedService (.NET Core 2.2)?'- это было название вопроса до обновления. Я решил изменить название после некоторых экспериментов. Я выполнил свою задачу с помощью обычного System.Timers
. Я покажу вам код.
Scheduler class
public class Scheduler
{
private const int MSecond = 1000;
private readonly int _seconds = MSecond * 10;
private Timer _aTimer;
public void Start()
{
Console.WriteLine("Sending is started ...");
_aTimer = new Timer();
_aTimer.Interval = _seconds;
_aTimer.Elapsed += OnTimedEvent;
_aTimer.AutoReset = true;
_aTimer.Enabled = true;
}
public bool IsWorking()
{
return _aTimer != null;
}
private void OnTimedEvent(object sender, ElapsedEventArgs e)
{
Console.WriteLine("Send ...");
}
public void Stop()
{
_aTimer.Stop();
_aTimer = null;
}
}
Controller
public class HomeController : Controller
{
private readonly Scheduler _scheduler;
public HomeController(Scheduler scheduler)
{
_scheduler = scheduler;
}
public IActionResult Index()
{
ViewBag.isSendingWorking = _scheduler.IsWorking();
return View();
}
public IActionResult Privacy()
{
return View();
}
public IActionResult On()
{
_scheduler.Start();
return Redirect(Url.Action("Index"));
}
public IActionResult Off()
{
_scheduler.Stop();
return Redirect(Url.Action("Index"));
}
}
И DI от Startup.cs
services.AddSingleton<Scheduler>();
Работает хорошо! И это решает задачу с запуском некоторого фонового задания. Поэтому я не понимаю, зачем нам HostedServices. Документация говорит мне, что HostedServices предназначен для фоновых задач с таймером тоже. ТАК какую прибыль я могу получить от HostedServices
? Или таймер лучше для моего случая? А может кто-нибудь поделиться опытом, как лучше решить эту задачу? Возможно, у меня будет только одна задача, но, может быть, в ближайшем будущем у меня будет больше фоновых задач.