In an ASP.net core application I spawn background tasks in one request, which can finish by themselves, or be cancelled by a second request. I have the following implementation, but I feel there should be a better way of achieving what I want? Does somebody have some experience with this problem?
public sealed class SomeService
{
    private record BackgroundTask(Task Task,
        CancellationTokenSource CancellationTokenSource);
    private readonly ConcurrentDictionary<Guid, BackgroundTask> _backgroundTasks
        = new();
    public void Start(Guid id)
    {
        var cancellationTokenSource = new CancellationTokenSource();
        var cancellationToken = cancellationTokenSource.Token;
        var task = Task.Run(async () =>
        {
            try
            {
                await Task.Delay(1000, cancellationToken);
            }
            finally
            {
                _backgroundTasks.TryRemove(id, out _);
            }
        }, cancellationToken);
        _backgroundTasks.TryAdd(id, new BackgroundTask(task, cancellationTokenSource));
    }
    public void Cancel(Guid id)
    {
        _backgroundTasks.TryGetValue(id, out var backgroundTask);
        if (backgroundTask == null)
        {
            return;
        }
        
        backgroundTask.CancellationTokenSource.Cancel();
        try
        {
            backgroundTask.Task.GetAwaiter().GetResult();
        }
        catch (OperationCanceledException e)
        {
            // todo: cancellation successful...
        }
    }
}