我怎样才能创建一个后台服务,它在每个给定的时间段运行一个函数?使用 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 中执行此操作:
它被称为工人服务。
您基本上实现了两个接口:IHostedService、IDisposable
然后在您的 Startup class 中在您的 ConfigureServices 方法中注册您的服务,如下所示:
services.AddHostedService<MyCoolWorkerServiceClass>();
最后一个建议。该示例使用 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);
}
}
}
}
我正在尝试每隔指定的时间间隔调用一个函数,对于使用后台服务的 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 中执行此操作:
它被称为工人服务。
您基本上实现了两个接口:IHostedService、IDisposable
然后在您的 Startup class 中在您的 ConfigureServices 方法中注册您的服务,如下所示:
services.AddHostedService<MyCoolWorkerServiceClass>();
最后一个建议。该示例使用 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);
}
}
}
}