首页 > 解决方案 > 如何创建在每个给定时间段运行功能的后台服务?使用 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 请求测试了该方法,它工作正常,将警报添加到我的数据库中:

在此处输入图像描述

我创建了一个服务,我在其中调用了该函数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);
        }
    }
}

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

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()函数并且它不起作用。

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

标签: c#asp.net-corebackground-service

解决方案


就我个人而言,我会重新安排您的解决方案,以便您的后台服务不需要创建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);
                }
            }
        }
    }

推荐阅读