如果我们有普通的System.Timers,为什么我们需要HostedServices?

时间:2019-10-08 17:01:47

标签: c# .net-core asp.net-core-hosted-services

我一直在阅读有关.NET Core和HostedServices的文档和文章。但是我不知道如何使用它。我的任务很普通。我有一些方法可以每60秒将推送通知发送到手机(通过Google FCM消息传递)。因此,我想:

  • 从我的控制器启动它;
  • 从我的控制器停止它;
  • 在视图上显示是否正在发送;
  • 使用.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"));
    }
}

还有Startup.cs的DI

services.AddSingleton<Scheduler>();

效果很好!并且它通过运行一些后台作业来解决任务。所以我不明白为什么我们需要HostedServices。文档告诉我HostedServices也打算用于带有计时器的后台任务。那我可以从HostedServices获得哪些利润?还是Timer更适合我的情况? 有人可以分享有关解决此任务的最佳方法的经验吗?也许我只有一项任务,但是也许在不久的将来,我将有更多的后台任务。

0 个答案:

没有答案