A .NET library for building dynamic, change-aware collection providers that aggregate multiple data sources with automatic change notifications.
ICollectionDataSource<T>- Interface for data sources that provide a collection of items with change token supportICollectionProvider<TItem, TCollection>- Interface for providers that aggregate multiple data sources into a unified collectionISupportChangeToken- Interface for objects that support change notification viaIChangeTokenINullChangeToken- Marker interface for change tokens that never signal changes
- Static Data Source - Wraps an immutable collection that never changes
- Observable Data Source - Wraps an
ObservableCollection<T>with automatic change notifications when items are added, removed, or modified - Composite Data Source - Aggregates multiple data sources into a single unified collection with consolidated change notifications
- Periodic Polling Data Source - Periodically fetches data from external sources (APIs, databases, files) with configurable refresh intervals and error handling
ICollectionDataSourceFactory- Creates data source instances for different scenariosICollectionProviderFactory- Creates collection provider instances that aggregate data sources
- Automatic propagation of change notifications from data sources to consumers
- Lazy initialization of change tokens for efficiency
- Thread-safe collection updates when changes are detected
- Support for additional change token producers beyond data sources (e.g., configuration changes)
AddCollectionProviders()extension method forIServiceCollection- Singleton registration of factories for optimal performance
- Support for DI-managed data source lifetimes
dotnet add package NCode.Collections.ProvidersOr for abstractions only:
dotnet add package NCode.Collections.Providers.Abstractionsservices.AddCollectionProviders();var factory = serviceProvider.GetRequiredService<ICollectionDataSourceFactory>();
var dataSource = factory.CreateStatic(new[] { "item1", "item2", "item3" });var observableCollection = new ObservableCollection<string>();
var dataSource = factory.CreateObservable(observableCollection);
// Changes to observableCollection will trigger change notifications
observableCollection.Add("new item");var dataSource = factory.CreatePeriodicPolling(
state: httpClient,
initialCollection: Array.Empty<User>(),
refreshInterval: TimeSpan.FromMinutes(5),
refreshCollectionAsync: async (client, current, ct) =>
{
var users = await client.GetFromJsonAsync<List<User>>("/api/users", ct);
return RefreshCollectionResultFactory.Changed(users);
},
handleExceptionAsync: async (ex, ct) =>
{
logger.LogError(ex.SourceException, "Failed to refresh users");
}
);var providerFactory = serviceProvider.GetRequiredService<ICollectionProviderFactory>();
var provider = providerFactory.Create(
collectionFactory: items => items.ToList(),
dataSources: serviceProvider.GetServices<ICollectionDataSource<User>>()
);
// Access the aggregated collection
var users = provider.Collection;
// Subscribe to changes
ChangeToken.OnChange(provider.GetChangeToken, () =>
{
Console.WriteLine("Collection changed!");
var updatedUsers = provider.Collection;
});Licensed under the Apache License, Version 2.0. See LICENSE.txt for details.
- .NET 8.0
- .NET 10.0
- v1.0.0 - Initial release