我怎样才能创建一个后台服务,它在每个给定的时间段运行一个函数?使用 C#(asp.net 核心 3.1.1)

How can I create a BackGround service that runs a function every given period of time ? Using C# (asp.net core 3.1.1)

我正在尝试每隔指定的时间间隔调用一个函数,对于使用后台服务的 m,这是我所做的: 这是我具有功能的警报控制器:

public class AlertingController : ControllerBase
{
    private readonly DatabaseContext _context;
    private readonly IMapper _mapper;

    public AlertingController(DatabaseContext context, IMapper mapper)
    {
        _context = context ?? throw new ArgumentNullException(nameof(context));
        _mapper = mapper ?? throw new ArgumentNullException(nameof(mapper));
    }
    public AlertingController()
    {

    }
//function that adds in the DB
    public async Task<AlertingResponse> GetAlertingToDB()
    {
        AlertingResponse dataGet;

        using (var httpClient = new HttpClient())
        {
            using (var response = await httpClient
                .GetAsync(MetricApiLink))
            {
                string apiResponse = await response.Content.ReadAsStringAsync();
                dataGet = JsonConvert.DeserializeObject<AlertingResponse>(apiResponse);
            }
        }
        if (dataGet.data.alerts != null || dataGet.data.alerts.Count > 0)
        {
            foreach (var alert in dataGet.data.alerts)
            {
                CreateAlertQuery QueryAlert = new CreateAlertQuery();
                QueryAlert.Name = alert.labels.alertname;
                QueryAlert.Instance = alert.labels.instance;
                QueryAlert.Serverity = alert.labels.severity;
                QueryAlert.Summary = alert.annotations.summary;
                QueryAlert.State = alert.state;
                QueryAlert.ActiveAt = alert.activeAt;
                var _Alert = _mapper.Map<AlertingDataModel>(QueryAlert);
                _context.Alertings.Add(_Alert);
                await _context.SaveChangesAsync();
            }
        }

        return null;
    }
}

我已经用 HTTPGET 请求测试了该方法,它工作正常,将警报添加到我的数据库中:

我创建了一个 scooped 服务,我在其中调用了函数 GetAlertingToDB():

    internal interface IScopedAlertingService
    {
        Task DoWork(CancellationToken stoppingToken);
    }
    public class ScopedAlertingService : IScopedAlertingService
    {
        private int executionCount = 0;
        private readonly ILogger _logger;

    public ScopedAlertingService(ILogger<ScopedAlertingService> logger)
    {
        _logger = logger;
    }

    public async Task DoWork(CancellationToken stoppingToken)
    {
        AlertingController _AlertingToDB = new AlertingController();
        while (!stoppingToken.IsCancellationRequested)
        {
            executionCount++;

            _logger.LogInformation(
                "Scoped Processing Service is working. Count: {Count}", executionCount);

            await _AlertingToDB.GetAlertingToDB();

            await Task.Delay(10000, stoppingToken);
        }
    }
}

我还创建了将使用我的服务的 Class,并将 运行 在后台:

public class ConsumeScopedServiceHostedService : BackgroundService
{
    private readonly ILogger<ConsumeScopedServiceHostedService> _logger;

    public ConsumeScopedServiceHostedService(IServiceProvider services,
        ILogger<ConsumeScopedServiceHostedService> logger)
    {
        Services = services;
        _logger = logger;
    }

    public IServiceProvider Services { get; }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        _logger.LogInformation(
            "Consume Scoped Service Hosted Service running.");

        await DoWork(stoppingToken);
    }

    private async Task DoWork(CancellationToken stoppingToken)
    {
        _logger.LogInformation(
            "Consume Scoped Service Hosted Service is working.");

        using (var scope = Services.CreateScope())
        {
            var scopedProcessingService =
                scope.ServiceProvider
                    .GetRequiredService<IScopedAlertingService>();

            await scopedProcessingService.DoWork(stoppingToken);
        }
    }

    public override async Task StopAsync(CancellationToken stoppingToken)
    {
        _logger.LogInformation(
            "Consume Scoped Service Hosted Service is stopping.");

        await Task.CompletedTask;
    }
}

我在 Startup Class 上注入了依赖项并添加了托管服务:

        services.AddHostedService<ConsumeScopedServiceHostedService>();
        services.AddScoped<IScopedAlertingService, ScopedAlertingService>();

函数工作正常,直到调用 GetAlertingToDB() 函数但它不起作用。

任何帮助都会很棒,谢谢大家:)

Hangfire RecurringJob 是您的一个选择。你可以在这里查看 https://docs.hangfire.io/en/latest/background-methods/performing-recurrent-tasks.html。 使用它的好处是:您有一个仪表板来检查何时触发任务以及任务的结果。

执行此操作有多种选择。

请阅读 Microsoft 文档中的以下 link,其中有几个示例说明如何在 .NET Core 和 ASP.NET Core 中执行此操作:

Worker Service In NET Core

它被称为工人服务。

您基本上实现了两个接口:IHostedService、IDisposable

然后在您的 Startup class 中在您的 ConfigureServices 方法中注册您的服务,如下所示:

services.AddHostedService<MyCoolWorkerServiceClass>();

一个Complete Example

最后一个建议。该示例使用 System.Threading.Timer... 但我认为最好使用 System.Timers.Timer with AutoReset = false.

原因是为了避免 运行 服务重叠。 运行 完成后,您将再次启动计时器。

不过话又说回来,这完全取决于您想要实现的目标。

我个人会重新安排您的解决方案,这样您的后台服务就不需要创建 Controller。相反,控制器,如果您仍然需要它,应该调用您的 ScopedAlertingService 执行一次工作。您的后台服务可以简单地永远循环,带有 await Task.Delay().

    public class ScopedAlertingService : IScopedAlertingService
    {
        public async Task DoWork(CancellationToken stoppingToken)
        {
            // move contents of your AlertingController.GetAlertingToDB here
        }
    }

    public class ConsumeScopedServiceHostedService : BackgroundService
    {
        private readonly IServiceProvider _services;
        public ConsumeScopedServiceHostedService(IServiceProvider services)
        {
            _services = services;
        }
        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                await Task.Delay(10000, stoppingToken);

                using (var scope = _services.CreateScope())
                {
                    var scopedProcessingService =
                        scope.ServiceProvider
                            .GetRequiredService<IScopedAlertingService>();

                    await scopedProcessingService.DoWork(stoppingToken);
                }
            }
        }
    }