-
Notifications
You must be signed in to change notification settings - Fork 5.4k
Description
Background and motivation
Today it's not possible to use ChangeToken.OnChange to execute asynchronous logic before re-subscribing for new updates. The current API has a Action<T> based callback only (https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.primitives.changetoken.onchange?view=dotnet-plat-ext-6.0). We need an async overload to run async logic so people don't end up using async void or blocking when using this helper.
API Proposal
namespace Microsoft.Extensions.Primitives;
public static class ChangeToken
{
public static IDisposable OnChange(Func<IChangeToken?> changeTokenProducer, Action changeTokenConsumer);
public static IDisposable OnChange<TState>(Func<IChangeToken?> changeTokenProducer, Action<TState> changeTokenConsumer, TState state);
+ public static IDisposable OnChange(Func<IChangeToken?> changeTokenProducer, Func<Task> changeTokenConsumer);
+ public static IDisposable OnChange<TState>(Func<IChangeToken?> changeTokenProducer, Func<TState, Task> changeTokenConsumer, TState state);
}API Usage
using Microsoft.Extensions.Primitives;
var config = new ConfigurationBuilder().AddJsonFile("config.json", optional: false, reloadOnChange: true)
.Build();
_ = ChangeToken.OnChange(config.GetReloadToken, async () =>
{
await Task.Delay(1000);
Console.WriteLine("Change happened");
});Alternatives (added by @svick)
- Add a
CancellationTokenparameter that's canceled when a following change is detected. This would probably be confusing, since not every caller would want to honor it and can be implemented by users if needed. - Change the name to
OnAsyncChange(or similar). For those that useasynclambda withOnChangetoday, this would be less breaking, but they wouldn't automatically get the benefit of the new version.
Risk (added by @svick)
This change means that existing code that uses an async lambda when calling OnChange will change meaning: previously, it compiled to an async void method; with this change, it will be an async Task method, where the callback is re-registered only once the returned Task completes. This could break some users, though the new behavior should be more correct.