-// Copyright (c) .NET Foundation. All rights reserved.
+// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
public abstract class BackgroundService : IHostedService, IDisposable
{
private Task _executingTask;
- private readonly CancellationTokenSource _stoppingCts = new CancellationTokenSource();
+ private CancellationTokenSource _stoppingCts;
/// <summary>
/// This method is called when the <see cref="IHostedService"/> starts. The implementation should return a task that represents
/// <param name="cancellationToken">Indicates that the start process has been aborted.</param>
public virtual Task StartAsync(CancellationToken cancellationToken)
{
+ // Create linked token to allow cancelling executing task from provided token
+ _stoppingCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
+
// Store the task we're executing
_executingTask = ExecuteAsync(_stoppingCts.Token);
public virtual void Dispose()
{
- _stoppingCts.Cancel();
+ _stoppingCts?.Cancel();
}
}
}
-using System;
+using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
service.Dispose();
}
+ [Fact]
+ public async Task StartAsyncThenCancelShouldCancelExecutingTask()
+ {
+ var tokenSource = new CancellationTokenSource();
+
+ var service = new WaitForCancelledTokenService();
+
+ await service.StartAsync(tokenSource.Token);
+
+ tokenSource.Cancel();
+
+ await Assert.ThrowsAsync<TaskCanceledException>(() => service.ExecutingTask);
+ }
+
+ [Fact]
+ public void CreateAndDisposeShouldNotThrow()
+ {
+ var service = new WaitForCancelledTokenService();
+
+ service.Dispose();
+ }
+
private class WaitForCancelledTokenService : BackgroundService
{
+ public Task ExecutingTask { get; private set; }
+
protected override Task ExecuteAsync(CancellationToken stoppingToken)
{
- return Task.Delay(Timeout.Infinite, stoppingToken);
+ ExecutingTask = Task.Delay(Timeout.Infinite, stoppingToken);
+ return ExecutingTask;
}
}