// 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.Collections.Generic; using System.Threading; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Primitives; namespace Microsoft.AspNetCore.Routing.TestObjects { public class DynamicEndpointDataSource : EndpointDataSource { private readonly List _endpoints; private CancellationTokenSource _cts; private CancellationChangeToken _changeToken; private readonly object _lock; public DynamicEndpointDataSource(params Endpoint[] endpoints) { _endpoints = new List(); _endpoints.AddRange(endpoints); _lock = new object(); CreateChangeToken(); } public override IChangeToken GetChangeToken() => _changeToken; public override IReadOnlyList Endpoints => _endpoints; // Trigger change public void AddEndpoint(Endpoint endpoint) { _endpoints.Add(endpoint); // Capture the old tokens so that we can raise the callbacks on them. This is important so that // consumers do not register callbacks on an inflight event causing a stackoverflow. var oldTokenSource = _cts; var oldToken = _changeToken; CreateChangeToken(); // Raise consumer callbacks. Any new callback registration would happen on the new token // created in earlier step. oldTokenSource.Cancel(); } private void CreateChangeToken() { _cts = new CancellationTokenSource(); _changeToken = new CancellationChangeToken(_cts.Token); } } }