我已经用asp.NET Core实现了REST API服务器。我需要执行一些管理工作的后台任务。
我尝试了网络中的一些建议以创建一个定时的后台任务,并将其实现为:BackgroundService.cs
public abstract class BackgroundService : IHostedService, IDisposable
{
private Task _executingTask;
private readonly CancellationTokenSource _stoppingCts = new CancellationTokenSource();
protected abstract Task ExecuteAsync(CancellationToken stoppingToken);
public virtual Task StartAsync(CancellationToken cancellationToken)
{
_executingTask = ExecuteAsync(_stoppingCts.Token);
if (_executingTask.IsCompleted)
{
return _executingTask;
}
return Task.CompletedTask;
}
public virtual async Task StopAsync(CancellationToken cancellationToken)
{
if (_executingTask == null)
{
return;
}
try
{
_stoppingCts.Cancel();
}
finally
{
await Task.WhenAny(_executingTask, Task.Delay(Timeout.Infinite, cancellationToken));
}
}
public virtual void Dispose()
{
_stoppingCts.Cancel();
}
}
RecureHostedService.cs
public class RecureHostedService : BackgroundService
{
private static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private int _executionCount = 0;
private Timer _timer;
protected async override Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
var count = Interlocked.Increment(ref _executionCount);
log.InfoFormat(
"Timed Hosted Service is working. Count: {0}", count);
await Task.Delay(10000, stoppingToken);
}
}
}
SystemController.cs
public class SystemController : Controller
{
private readonly RecureHostedService _recureHostedService;
public SystemController(IHostedService hostedService)
{
_recureHostedService = hostedService as RecureHostedService;
}
[HttpGet(ApiRoutes.System.Start)]
public IActionResult Start()
{
Console.WriteLine("Start Service");
_recureHostedService.StartAsync(new CancellationToken());
return Ok();
}
[HttpGet(ApiRoutes.System.Stop)]
public IActionResult Stop()
{
Console.WriteLine("Stop Service");
Console.WriteLine(_recureHostedService == null);
_recureHostedService.StopAsync(new CancellationToken());
return Ok();
}
}
在Startup.cs中,我将该服务添加为Singleton:
services.AddSingleton<IHostedService,RecureHostedService>();
RecureHostedService在我的应用程序启动时开始工作。当我从SystemController执行APIrequest / api / v1 / stop(方法Stop())时,在
中得到了NullReferenceException_recureHostedService.StopAsync(new CancellationToken());
我发现私有成员变量_recureHostedService为null,即使我已经在SystemController的构造函数中为其分配了它。因此,看来_recureHostedService的服务注入无效。所以这行
_recureHostedService = hostedService as RecureHostedService;
在SystemController的构造方法中,将_recureHostedService分配为null。怎么可能?我已经将许多其他服务注入其他控制器,并且一切正常。任何人的想法,为什么它不能与该托管服务一起使用?
最佳麦克风
您需要使用AddHostedService
的AddSingleton
安装程序注册托管服务所以会是这样
services.AddHostedService<IHostedService,RecureHostedService>();
如果您在构造函数上注入IHostedService,请保持声明为[[IHostedService类型的_recureHostedService
属性,而不是具体的类RecureHostedService。这里没有必要向下转换。
[Route("[controller]")]
public class SystemController : Controller
{
private readonly IHostedService _recureHostedService;
public SystemController(IHostedService hostedService)
{
_recureHostedService = hostedService ?? throw new ArgumentNullException(nameof(hostedService));
}
}
更新
我已经测试了该控制器,无论哪种方式都不再存在null异常
services.AddSingleton<IHostedService, RecureHostedService>();
或
services.AddHostedService(p => { return new RecureHostedService(); });
services.AddSingleton<RecureHostedService>();
services.AddSingleton<IHostedService>(p => p.GetRequiredService<RecureHostedService>());
public class SystemController : Controller
{
private readonly RecureHostedService _recureHostedService;
public SystemController(RecureHostedService hostedService)
{
_recureHostedService = hostedService;
}
}
public class RecureHostedService : BackgroundService {
public static bool isPause = false;
/* for example
public static string ErrorText;
public static bool isError = false;
public static bool isWorked = false;
public static bool firstStart = true; */
protected async override Task ExecuteAsync(CancellationToken stoppingToken){
while (!stoppingToken.IsCancellationRequested)
{
await Task.Delay(TimeSpan.FromSeconds(1), stoppingToken);
if (isPause)
continue;
var count = Interlocked.Increment(ref _executionCount);
log.InfoFormat(
"Timed Hosted Service is working. Count: {0}", count);
await Task.Delay(10000, stoppingToken);
}
}
}
public class SystemController : Controller
{
[HttpGet(ApiRoutes.System.Start)]
public IActionResult Start()
{
Console.WriteLine("Start Service");
RecureHostedService.isPause = false;
return Ok();
}
[HttpGet(ApiRoutes.System.Stop)]
public IActionResult Stop()
{
Console.WriteLine("Stop Service");
RecureHostedService.isPause = true;
return Ok();
}
}