From 06ea0cf675d9364b6d5456f3d37dcf02dec8a5a8 Mon Sep 17 00:00:00 2001 From: David Date: Thu, 30 Nov 2023 16:35:45 -0500 Subject: [PATCH] chore: Comply with CA2007 --- .../Presentation/Bindings/BindableListFeed.cs | 12 +++++----- .../Facets/LoadMoreItemsRequest.cs | 2 +- .../Collections/Services/EditionService.cs | 8 +++---- .../Collections/Services/PaginationService.cs | 4 ++-- .../Services/SingletonServiceProvider.cs | 2 +- .../Dispatching/DispatcherQueueProvider.cs | 4 ++-- src/Uno.Extensions.Reactive/.editorconfig | 2 +- src/Uno.Extensions.Reactive/Core/Feed.T.cs | 2 +- src/Uno.Extensions.Reactive/Core/Feed.cs | 22 ++++++++++++------- src/Uno.Extensions.Reactive/Core/IFeed.cs | 5 +++-- .../Core/Internal/FeedSubscription.cs | 4 ++-- .../Core/Internal/SourceContext.cs | 2 +- .../Core/Internal/StateImpl.cs | 4 ++-- .../Core/ListFeed.Extensions.cs | 8 +++---- .../Core/ListState.Extensions.cs | 8 +++---- .../Operators/HotSwapFeed.cs | 4 +++- .../Operators/ListFeedSelection.cs | 2 +- .../Operators/SelectAsyncFeed.cs | 2 +- .../Operators/StateForEach.cs | 2 +- .../Presentation/Bindings/Bindable.cs | 4 ++-- .../Bindings/BindableEnumerable.cs | 2 +- .../Bindings/BindablePropertyInfo.cs | 2 +- .../Bindings/BindableViewModelBase.cs | 4 ++-- .../Commands/AsyncCommand.SubCommand.cs | 12 +++++----- .../Sources/AsyncFeed.cs | 2 +- .../Dependencies/Feed/FeedDependency.cs | 4 ++-- .../Pagination/PaginationDependency.cs | 4 ++-- .../Sources/Dynamic/DynamicFeed.cs | 6 +++-- .../Sources/Dynamic/FeedExecution.cs | 5 +++++ .../Dynamic/FeedSession.T.Execution.cs | 18 +++++++-------- .../Utils/AsyncEnumerables/ForEachRunner.cs | 2 +- .../RefCountedForEachRunner.cs | 2 +- .../LastWinsAsyncOperationManager.cs | 2 +- .../SequentialAsyncOperationsManager.cs | 2 +- .../Disposables/CompositeAsyncDisposable.cs | 2 +- .../Utils/OptionExtensions.cs | 6 ++--- 36 files changed, 97 insertions(+), 81 deletions(-) diff --git a/src/Uno.Extensions.Reactive.UI/Presentation/Bindings/BindableListFeed.cs b/src/Uno.Extensions.Reactive.UI/Presentation/Bindings/BindableListFeed.cs index e4dea69f65..534b6000f3 100644 --- a/src/Uno.Extensions.Reactive.UI/Presentation/Bindings/BindableListFeed.cs +++ b/src/Uno.Extensions.Reactive.UI/Presentation/Bindings/BindableListFeed.cs @@ -172,18 +172,18 @@ async ValueTask LoadMore(uint desiredCount, CancellationToken ct) { var originalCount = currentCount; - await pageTokens.WaitFor(requests.RequestMoreItems(desiredCount), ct); + await pageTokens.WaitFor(requests.RequestMoreItems(desiredCount), ct).ConfigureAwait(false); var resultCount = currentCount; return (uint)Math.Max(0, resultCount - originalCount); } - async ValueTask SetSelected(SelectionInfo info, CancellationToken ct) - => await state.UpdateMessageAsync(msg => msg.Selected(info).Set(BindableViewModelBase.BindingSource, collection), ct); + ValueTask SetSelected(SelectionInfo info, CancellationToken ct) + => state.UpdateMessageAsync(msg => msg.Selected(info).Set(BindableViewModelBase.BindingSource, collection), ct); - async ValueTask Edit(Func change, CancellationToken ct) - => await state.UpdateMessageAsync( + ValueTask Edit(Func change, CancellationToken ct) + => state.UpdateMessageAsync( msg => { // Note: The change might have been computed on an older version of the collection @@ -209,6 +209,6 @@ async ValueTask Edit(Func public async ValueTask DisposeAsync() { - await _state.DisposeAsync(); + await _state.DisposeAsync().ConfigureAwait(false); } } diff --git a/src/Uno.Extensions.Reactive.UI/Presentation/Bindings/Collections/Facets/LoadMoreItemsRequest.cs b/src/Uno.Extensions.Reactive.UI/Presentation/Bindings/Collections/Facets/LoadMoreItemsRequest.cs index e36d508780..a7dd451532 100644 --- a/src/Uno.Extensions.Reactive.UI/Presentation/Bindings/Collections/Facets/LoadMoreItemsRequest.cs +++ b/src/Uno.Extensions.Reactive.UI/Presentation/Bindings/Collections/Facets/LoadMoreItemsRequest.cs @@ -35,7 +35,7 @@ public async Task GetLoaded() { try { - return (await _result.Task).Count; + return (await _result.Task.ConfigureAwait(false)).Count; } catch (OperationCanceledException) { diff --git a/src/Uno.Extensions.Reactive.UI/Presentation/Bindings/Collections/Services/EditionService.cs b/src/Uno.Extensions.Reactive.UI/Presentation/Bindings/Collections/Services/EditionService.cs index f9f1cdb405..f8fbcf1286 100644 --- a/src/Uno.Extensions.Reactive.UI/Presentation/Bindings/Collections/Services/EditionService.cs +++ b/src/Uno.Extensions.Reactive.UI/Presentation/Bindings/Collections/Services/EditionService.cs @@ -37,8 +37,8 @@ public void Update(Func(); using var _ = _ct.Token.Register(() => tcs.TrySetCanceled()); dispatcher.TryEnqueue(() => tcs.TrySetResult(default)); - await tcs.Task; - await Dequeue(); + await tcs.Task.ConfigureAwait(false); + await Dequeue().ConfigureAwait(false); }, _ct.Token); } @@ -51,12 +51,12 @@ public void Update(Func>.Empty); foreach (var edition in editions) { - await _editFromView(edition, _ct.Token); + await _editFromView(edition, _ct.Token).ConfigureAwait(false); } } diff --git a/src/Uno.Extensions.Reactive.UI/Presentation/Bindings/Collections/Services/PaginationService.cs b/src/Uno.Extensions.Reactive.UI/Presentation/Bindings/Collections/Services/PaginationService.cs index 0df0160ae4..013cc983ca 100644 --- a/src/Uno.Extensions.Reactive.UI/Presentation/Bindings/Collections/Services/PaginationService.cs +++ b/src/Uno.Extensions.Reactive.UI/Presentation/Bindings/Collections/Services/PaginationService.cs @@ -67,9 +67,9 @@ public async Task LoadMoreItems(uint count, CancellationToken ct) throw new ObjectDisposedException(nameof(PaginationService)); } - using (await _gate.LockAsync(ct)) + using (await _gate.LockAsync(ct).ConfigureAwait(false)) { - return await new LoadRequest(this, count).GetResult(ct); + return await new LoadRequest(this, count).GetResult(ct).ConfigureAwait(false); } } diff --git a/src/Uno.Extensions.Reactive.UI/Presentation/Bindings/Collections/Services/SingletonServiceProvider.cs b/src/Uno.Extensions.Reactive.UI/Presentation/Bindings/Collections/Services/SingletonServiceProvider.cs index 197a8dae87..d07e1f9d79 100644 --- a/src/Uno.Extensions.Reactive.UI/Presentation/Bindings/Collections/Services/SingletonServiceProvider.cs +++ b/src/Uno.Extensions.Reactive.UI/Presentation/Bindings/Collections/Services/SingletonServiceProvider.cs @@ -26,7 +26,7 @@ public async ValueTask DisposeAsync() switch (service) { case IAsyncDisposable asyncDisposable: - await asyncDisposable.DisposeAsync(); + await asyncDisposable.DisposeAsync().ConfigureAwait(false); break; case IDisposable disposable: diff --git a/src/Uno.Extensions.Reactive.UI/Utils/Dispatching/DispatcherQueueProvider.cs b/src/Uno.Extensions.Reactive.UI/Utils/Dispatching/DispatcherQueueProvider.cs index 3a8cd2ae23..821325330a 100644 --- a/src/Uno.Extensions.Reactive.UI/Utils/Dispatching/DispatcherQueueProvider.cs +++ b/src/Uno.Extensions.Reactive.UI/Utils/Dispatching/DispatcherQueueProvider.cs @@ -47,13 +47,13 @@ public async ValueTask ExecuteAsync(AsyncFunc action, TryEnqueue(Execute); - return await tcs.Task; + return await tcs.Task.ConfigureAwait(false); async void Execute() { try { - tcs.TrySetResult(await action(ct)); + tcs.TrySetResult(await action(ct).ConfigureAwait(false)); } catch (Exception error) { diff --git a/src/Uno.Extensions.Reactive/.editorconfig b/src/Uno.Extensions.Reactive/.editorconfig index d059184749..9472d4b922 100644 --- a/src/Uno.Extensions.Reactive/.editorconfig +++ b/src/Uno.Extensions.Reactive/.editorconfig @@ -1,5 +1,5 @@ root = false [*.cs] -dotnet_diagnostic.CA2007.severity = suggestion +dotnet_diagnostic.CA2007.severity = error dotnet_diagnostic.CA2016.severity = error diff --git a/src/Uno.Extensions.Reactive/Core/Feed.T.cs b/src/Uno.Extensions.Reactive/Core/Feed.T.cs index f7d48cbd5a..8f0a53ae97 100644 --- a/src/Uno.Extensions.Reactive/Core/Feed.T.cs +++ b/src/Uno.Extensions.Reactive/Core/Feed.T.cs @@ -11,7 +11,7 @@ namespace Uno.Extensions.Reactive; /// Provides a set of static methods to create and manipulate . /// /// The type of the data. -public static class Feed // We set the T on the class to it greatly helps type inference of factory delegates +public static partial class Feed // We set the T on the class to it greatly helps type inference of factory delegates { /// /// Gets or create a custom feed from an async method. diff --git a/src/Uno.Extensions.Reactive/Core/Feed.cs b/src/Uno.Extensions.Reactive/Core/Feed.cs index f3a6d3144a..fe490170a3 100644 --- a/src/Uno.Extensions.Reactive/Core/Feed.cs +++ b/src/Uno.Extensions.Reactive/Core/Feed.cs @@ -242,10 +242,13 @@ static IFeed> Create(IFeed parameter, AsyncFunc return ImmutableList.Empty; } - var items = await FeedExecution.Current!.GetPaginated( - b => b - .ByIndex() - .GetPage((req, ct) => gp(value, req, ct))); + var items = await FeedExecution + .Current + !.GetPaginated( + b => b + .ByIndex() + .GetPage((req, ct) => gp(value, req, ct))) + .ConfigureAwait(false); return items; }); @@ -280,10 +283,13 @@ static IFeed> Create(IFeed parameter, (TCursor return ImmutableList.Empty; } - var items = await FeedExecution.Current!.GetPaginated( - b => b - .ByCursor(args.firstPage) - .GetPage((token, count, ct) => args.getPage(value, token, count, ct))); + var items = await FeedExecution + .Current + !.GetPaginated( + b => b + .ByCursor(args.firstPage) + .GetPage((token, count, ct) => args.getPage(value, token, count, ct))) + .ConfigureAwait(false); return items; }); diff --git a/src/Uno.Extensions.Reactive/Core/IFeed.cs b/src/Uno.Extensions.Reactive/Core/IFeed.cs index cfd799cf3e..0907cd8244 100644 --- a/src/Uno.Extensions.Reactive/Core/IFeed.cs +++ b/src/Uno.Extensions.Reactive/Core/IFeed.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using System.Runtime.CompilerServices; namespace Uno.Extensions.Reactive; @@ -7,7 +8,7 @@ namespace Uno.Extensions.Reactive; /// A **stateless** stream of data. /// /// The type of the data. -public interface IFeed : ISignal> - /* where T : record */ +public partial interface IFeed : ISignal> + /* where T : record or struct */ { } diff --git a/src/Uno.Extensions.Reactive/Core/Internal/FeedSubscription.cs b/src/Uno.Extensions.Reactive/Core/Internal/FeedSubscription.cs index e6eff8505d..8b79ff03cc 100644 --- a/src/Uno.Extensions.Reactive/Core/Internal/FeedSubscription.cs +++ b/src/Uno.Extensions.Reactive/Core/Internal/FeedSubscription.cs @@ -83,8 +83,8 @@ public async IAsyncEnumerable> GetMessages(SourceContext subscriberCo /// public async ValueTask DisposeAsync() { - await _context.DisposeAsync(); + await _context.DisposeAsync().ConfigureAwait(false); _requests.Dispose(); - await _messages.DisposeAsync(); + await _messages.DisposeAsync().ConfigureAwait(false); } } diff --git a/src/Uno.Extensions.Reactive/Core/Internal/SourceContext.cs b/src/Uno.Extensions.Reactive/Core/Internal/SourceContext.cs index 9a5dd06224..65f143316f 100644 --- a/src/Uno.Extensions.Reactive/Core/Internal/SourceContext.cs +++ b/src/Uno.Extensions.Reactive/Core/Internal/SourceContext.cs @@ -410,7 +410,7 @@ public async ValueTask DisposeAsync() // Note: We make sure dispose only the values explicitly defined on this context, // but not those that are inherited from the parent context. - await (_localStates?.DisposeAsync() ?? default); + await (_localStates?.DisposeAsync() ?? default).ConfigureAwait(false); _localRequests?.Dispose(); } catch (Exception) { } diff --git a/src/Uno.Extensions.Reactive/Core/Internal/StateImpl.cs b/src/Uno.Extensions.Reactive/Core/Internal/StateImpl.cs index ab392bb45f..44457f8a9a 100644 --- a/src/Uno.Extensions.Reactive/Core/Internal/StateImpl.cs +++ b/src/Uno.Extensions.Reactive/Core/Internal/StateImpl.cs @@ -118,7 +118,7 @@ public async ValueTask UpdateMessageAsync(Action> updater, Can var update = new Update(updater, _updatesKind); _inner.Add(update); - await update.HasBeenApplied; // Makes sure to forward (the first) error to the caller if any. + await update.HasBeenApplied.ConfigureAwait(false); // Makes sure to forward (the first) error to the caller if any. } private void Enable() @@ -144,7 +144,7 @@ public async ValueTask DisposeAsync() // This is a temporary patch until we support dynamic updates of the subscription mode in FeedSubscription (i.e. the _subscriptionMode). if (_subscription is { } sub) { - await sub.DisposeAsync(); + await sub.DisposeAsync().ConfigureAwait(false); } _subscriptionMode?.Dispose(); } diff --git a/src/Uno.Extensions.Reactive/Core/ListFeed.Extensions.cs b/src/Uno.Extensions.Reactive/Core/ListFeed.Extensions.cs index 8fe235c0f6..d78e7a14d8 100644 --- a/src/Uno.Extensions.Reactive/Core/ListFeed.Extensions.cs +++ b/src/Uno.Extensions.Reactive/Core/ListFeed.Extensions.cs @@ -80,7 +80,7 @@ public static async ValueTask>> Option(this IListFee => await FeedDependency.TryGetCurrentMessage(listFeed).ConfigureAwait(false) switch { { } message => message.Current.EnsureNoError().Data, - null => await listFeed.Options(AsyncFeedValue.Default, ct).FirstOrDefaultAsync(Extensions.Option>.Undefined(), ct) + null => await listFeed.Options(AsyncFeedValue.Default, ct).FirstOrDefaultAsync(Extensions.Option>.Undefined(), ct).ConfigureAwait(false) }; /// @@ -96,7 +96,7 @@ public static async ValueTask>> Option(this IListFee { not null when kind is not AsyncFeedValue.Default => throw new NotSupportedException($"Only kind AsyncFeedValue.Default is currently supported by the dynamic feed (requested: {kind})."), { } message => message.Current.EnsureNoError().Data, - null => await listFeed.Options(kind, ct).FirstOrDefaultAsync(Extensions.Option>.Undefined(), ct) + null => await listFeed.Options(kind, ct).FirstOrDefaultAsync(Extensions.Option>.Undefined(), ct).ConfigureAwait(false) }; /// @@ -234,7 +234,7 @@ public static IFeed> AsFeed( /// The selected items, or an empty collection if none. [EditorBrowsable(EditorBrowsableState.Never)] public static async ValueTask> GetSelectedItems(this IListFeed source, CancellationToken ct) - => (await source.Message(ct)).Current.GetSelectedItems(); + => (await source.Message(ct).ConfigureAwait(false)).Current.GetSelectedItems(); /// /// Gets the selected item of a list feed, or null if none. @@ -246,5 +246,5 @@ public static async ValueTask> GetSelectedItems(this IListF [EditorBrowsable(EditorBrowsableState.Never)] public static async ValueTask GetSelectedItem(this IListFeed source, CancellationToken ct) where T : notnull - => (await source.Message(ct)).Current.GetSelectedItem(); + => (await source.Message(ct).ConfigureAwait(false)).Current.GetSelectedItem(); } diff --git a/src/Uno.Extensions.Reactive/Core/ListState.Extensions.cs b/src/Uno.Extensions.Reactive/Core/ListState.Extensions.cs index 4e554e837b..0cc1c04718 100644 --- a/src/Uno.Extensions.Reactive/Core/ListState.Extensions.cs +++ b/src/Uno.Extensions.Reactive/Core/ListState.Extensions.cs @@ -228,7 +228,7 @@ await state.UpdateMessageAsync(msg => success = true; msg.Selected(selection); } - }, ct); + }, ct).ConfigureAwait(false); return success; } @@ -255,7 +255,7 @@ await state.UpdateMessageAsync(msg => success = true; msg.Selected(selection); } - }, ct); + }, ct).ConfigureAwait(false); return success; } @@ -267,9 +267,9 @@ await state.UpdateMessageAsync(msg => /// The state to update. /// A token to abort the async operation. /// - public static async ValueTask ClearSelectionAsync(this IListState state, CancellationToken ct = default) + public static ValueTask ClearSelectionAsync(this IListState state, CancellationToken ct = default) where T : notnull - => await state.UpdateMessageAsync(msg => msg.Selected(SelectionInfo.Empty), ct); + => state.UpdateMessageAsync(msg => msg.Selected(SelectionInfo.Empty), ct); /// /// [DEPRECATED] Use .ClearSelectionAsync instead diff --git a/src/Uno.Extensions.Reactive/Operators/HotSwapFeed.cs b/src/Uno.Extensions.Reactive/Operators/HotSwapFeed.cs index 354a05512e..777f37ee39 100644 --- a/src/Uno.Extensions.Reactive/Operators/HotSwapFeed.cs +++ b/src/Uno.Extensions.Reactive/Operators/HotSwapFeed.cs @@ -63,7 +63,9 @@ public void Set(ISignal>? feed) /// public async IAsyncEnumerable> GetSource(SourceContext context, [EnumeratorCancellation] CancellationToken ct = default) { +#pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task, false positive: it's for the DisposeAsync which cannot be configured here await using var session = new Session(this, context, ct); +#pragma warning restore CA2007 while (await session.MoveNextAsync().ConfigureAwait(false)) { yield return session.Current; @@ -109,7 +111,7 @@ public async ValueTask MoveNextAsync() { var moveNext = enumerator.MoveNextAsync().AsTask(); if (await Task.WhenAny(moveNext, next.Task).ConfigureAwait(false) == moveNext - && await moveNext) + && await moveNext.ConfigureAwait(false)) { var canSkip = !_isFirstMessage && _isFirstMessageOfCurrentEnumerator; diff --git a/src/Uno.Extensions.Reactive/Operators/ListFeedSelection.cs b/src/Uno.Extensions.Reactive/Operators/ListFeedSelection.cs index d20bf32bf4..45ab2085b5 100644 --- a/src/Uno.Extensions.Reactive/Operators/ListFeedSelection.cs +++ b/src/Uno.Extensions.Reactive/Operators/ListFeedSelection.cs @@ -199,7 +199,7 @@ public async ValueTask DisposeAsync() _ct.Cancel(); if (_impl is not null) { - await _impl.DisposeAsync(); + await _impl.DisposeAsync().ConfigureAwait(false); } } } diff --git a/src/Uno.Extensions.Reactive/Operators/SelectAsyncFeed.cs b/src/Uno.Extensions.Reactive/Operators/SelectAsyncFeed.cs index 6fbe065fba..68a8bd84a2 100644 --- a/src/Uno.Extensions.Reactive/Operators/SelectAsyncFeed.cs +++ b/src/Uno.Extensions.Reactive/Operators/SelectAsyncFeed.cs @@ -65,7 +65,7 @@ async void BeginEnumeration() if (projection is not null) { // Make sure to await the end of the last projection before completing the subject! - await projection; + await projection.ConfigureAwait(false); } subject.Complete(); } diff --git a/src/Uno.Extensions.Reactive/Operators/StateForEach.cs b/src/Uno.Extensions.Reactive/Operators/StateForEach.cs index a7abfccdcf..698804d4d7 100644 --- a/src/Uno.Extensions.Reactive/Operators/StateForEach.cs +++ b/src/Uno.Extensions.Reactive/Operators/StateForEach.cs @@ -49,7 +49,7 @@ private async Task Execute(T? value, CancellationToken ct) try { - await _action(value, ct); + await _action(value, ct).ConfigureAwait(false); } catch (OperationCanceledException) when (ct.IsCancellationRequested) { diff --git a/src/Uno.Extensions.Reactive/Presentation/Bindings/Bindable.cs b/src/Uno.Extensions.Reactive/Presentation/Bindings/Bindable.cs index 8ee79133d3..aad4f20973 100644 --- a/src/Uno.Extensions.Reactive/Presentation/Bindings/Bindable.cs +++ b/src/Uno.Extensions.Reactive/Presentation/Bindings/Bindable.cs @@ -209,7 +209,7 @@ private async void UpdateOwner(T value) _asyncSetCt?.Cancel(); _asyncSetCt = new(); - await _property.Update(_ => value, true, _asyncSetCt.Token); + await _property.Update(_ => value, true, _asyncSetCt.Token).ConfigureAwait(false); } catch (OperationCanceledException) { @@ -247,7 +247,7 @@ private async ValueTask OnSubPropertyUpdated( // 2. Propagate the update to the parent (i.e. update the backing state) // Note: We re-invoke the 'update' delegate here (instead of using the '_value') to make sure to respect ACID - await _property.Update(t => set(t, update(get(t))), false, ct); + await _property.Update(t => set(t, update(get(t))), false, ct).ConfigureAwait(false); } } diff --git a/src/Uno.Extensions.Reactive/Presentation/Bindings/BindableEnumerable.cs b/src/Uno.Extensions.Reactive/Presentation/Bindings/BindableEnumerable.cs index 6f0019193f..c831f0e36e 100644 --- a/src/Uno.Extensions.Reactive/Presentation/Bindings/BindableEnumerable.cs +++ b/src/Uno.Extensions.Reactive/Presentation/Bindings/BindableEnumerable.cs @@ -172,7 +172,7 @@ async ValueTask OnItemUpdated(Func updater, bool isLeafPropertyCha _owner.RaisePropertyChanged($"Item[{CurrentIndex}]"); } - await _owner._listProperty.Update(list => _owner.Replace(list, previous, updated), false, ct); + await _owner._listProperty.Update(list => _owner.Replace(list, previous, updated), false, ct).ConfigureAwait(false); } } diff --git a/src/Uno.Extensions.Reactive/Presentation/Bindings/BindablePropertyInfo.cs b/src/Uno.Extensions.Reactive/Presentation/Bindings/BindablePropertyInfo.cs index 20f10633c7..41d7325096 100644 --- a/src/Uno.Extensions.Reactive/Presentation/Bindings/BindablePropertyInfo.cs +++ b/src/Uno.Extensions.Reactive/Presentation/Bindings/BindablePropertyInfo.cs @@ -56,7 +56,7 @@ public async ValueTask Update(Func updater, bool isLeafPropertyChanged, Ca { if (CanWrite) { - await _update!(updater, isLeafPropertyChanged, ct); + await _update!(updater, isLeafPropertyChanged, ct).ConfigureAwait(false); } } } diff --git a/src/Uno.Extensions.Reactive/Presentation/Bindings/BindableViewModelBase.cs b/src/Uno.Extensions.Reactive/Presentation/Bindings/BindableViewModelBase.cs index cd246bed04..163ce9321f 100644 --- a/src/Uno.Extensions.Reactive/Presentation/Bindings/BindableViewModelBase.cs +++ b/src/Uno.Extensions.Reactive/Presentation/Bindings/BindableViewModelBase.cs @@ -133,7 +133,7 @@ async void ViewModelToView(Action updated) updated(initialValue); var ct = stateImpl.Context.Token; var source = FeedUIHelper.GetSource(stateImpl, stateImpl.Context); - var dispatcher = await _dispatcher.GetFirstResolved(ct); + var dispatcher = await _dispatcher.GetFirstResolved(ct).ConfigureAwait(false); dispatcher.TryEnqueue(async () => { @@ -206,7 +206,7 @@ protected ILogger __Reactive_Log() /// public async ValueTask DisposeAsync() { - await _disposables.DisposeAsync(); + await _disposables.DisposeAsync().ConfigureAwait(false); _propertyChanged.Dispose(); _dispatcher.Dispose(); } diff --git a/src/Uno.Extensions.Reactive/Presentation/Commands/AsyncCommand.SubCommand.cs b/src/Uno.Extensions.Reactive/Presentation/Commands/AsyncCommand.SubCommand.cs index c6195e30e5..404a6229aa 100644 --- a/src/Uno.Extensions.Reactive/Presentation/Commands/AsyncCommand.SubCommand.cs +++ b/src/Uno.Extensions.Reactive/Presentation/Commands/AsyncCommand.SubCommand.cs @@ -114,12 +114,12 @@ public bool TryExecute(object? viewParameter, SourceContext context, Cancellatio var completed = 0; var task = Task.Run( - async () => - { - using var _ = context.AsCurrent(); - await _config.Execute(coercedParameter, ct); - }, - ct); + async () => + { + using var _ = context.AsCurrent(); + await _config.Execute(coercedParameter, ct).ConfigureAwait(false); + }, + ct); // Note: As the CT is cancelled when the command is disposed, we have to use a registration instead of a continuation // to make sure `ReportExecutionEnded` is run synchronously so before the EventManager is being disposed! diff --git a/src/Uno.Extensions.Reactive/Sources/AsyncFeed.cs b/src/Uno.Extensions.Reactive/Sources/AsyncFeed.cs index dbdf38b0d1..dd2d5ac6a5 100644 --- a/src/Uno.Extensions.Reactive/Sources/AsyncFeed.cs +++ b/src/Uno.Extensions.Reactive/Sources/AsyncFeed.cs @@ -110,7 +110,7 @@ async void BeginEnumeration() if (load is not null) { // Make sure to await the end of the last projection before completing the subject! - await load; + await load.ConfigureAwait(false); } subject.Complete(); } diff --git a/src/Uno.Extensions.Reactive/Sources/Dynamic/Dependencies/Feed/FeedDependency.cs b/src/Uno.Extensions.Reactive/Sources/Dynamic/Dependencies/Feed/FeedDependency.cs index 2410781045..a906e35a97 100644 --- a/src/Uno.Extensions.Reactive/Sources/Dynamic/Dependencies/Feed/FeedDependency.cs +++ b/src/Uno.Extensions.Reactive/Sources/Dynamic/Dependencies/Feed/FeedDependency.cs @@ -12,12 +12,12 @@ internal abstract class FeedDependency public static async ValueTask?> TryGetCurrentMessage(IFeed feed) => FeedExecution.Current is { } exec - ? await exec.Session.Feeds.Get(feed, exec).GetCurrentMessage(exec) + ? await exec.Session.Feeds.Get(feed, exec).GetCurrentMessage(exec).ConfigureAwait(false) : null; public static async ValueTask>?> TryGetCurrentMessage(IListFeed feed) => FeedExecution.Current is { } exec - ? await exec.Session.Feeds.Get(feed, exec).GetCurrentMessage(exec) + ? await exec.Session.Feeds.Get(feed, exec).GetCurrentMessage(exec).ConfigureAwait(false) : null; public static void NotifyTouched(IMessageEntry entry, MessageAxis axis) diff --git a/src/Uno.Extensions.Reactive/Sources/Dynamic/Dependencies/Pagination/PaginationDependency.cs b/src/Uno.Extensions.Reactive/Sources/Dynamic/Dependencies/Pagination/PaginationDependency.cs index 47434e6599..dd772273b9 100644 --- a/src/Uno.Extensions.Reactive/Sources/Dynamic/Dependencies/Pagination/PaginationDependency.cs +++ b/src/Uno.Extensions.Reactive/Sources/Dynamic/Dependencies/Pagination/PaginationDependency.cs @@ -101,7 +101,7 @@ public async ValueTask> GetItems(FeedExecution exec _gotItems = true; - using (await _gate.LockAsync(_ct.Token)) + using (await _gate.LockAsync(_ct.Token).ConfigureAwait(false)) { var (isPagination, req) = FindPaginationRequest(exec); if (_pages is null // Initial load (req is then expected to be an InitialLoadRequest) @@ -118,7 +118,7 @@ public async ValueTask> GetItems(FeedExecution exec return _items; } - if (await _pages.MoveNextAsync(req?.DesiredPageSize)) + if (await _pages.MoveNextAsync(req?.DesiredPageSize).ConfigureAwait(false)) { // No needs to configure the _pageInfo, it has been done in the OnLoading method. _items = _items.AddRange(_pages.Current); diff --git a/src/Uno.Extensions.Reactive/Sources/Dynamic/DynamicFeed.cs b/src/Uno.Extensions.Reactive/Sources/Dynamic/DynamicFeed.cs index 072be8316a..afd65a9edb 100644 --- a/src/Uno.Extensions.Reactive/Sources/Dynamic/DynamicFeed.cs +++ b/src/Uno.Extensions.Reactive/Sources/Dynamic/DynamicFeed.cs @@ -14,7 +14,7 @@ internal sealed class DynamicFeed : IFeed public DynamicFeed(AsyncFunc dataProvider) { - _dataProvider = async ct => Option.SomeOrNone(await dataProvider(ct)); + _dataProvider = async ct => Option.SomeOrNone(await dataProvider(ct).ConfigureAwait(false)); } public DynamicFeed(AsyncFunc> dataProvider) @@ -25,9 +25,11 @@ public DynamicFeed(AsyncFunc> dataProvider) /// public async IAsyncEnumerable> GetSource(SourceContext context, [EnumeratorCancellation] CancellationToken ct = default) { +#pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task, false positive: it's for the DisposeAsync which cannot be configured here await using var session = new FeedSession(this, context, _dataProvider, ct); +#pragma warning restore CA2007 - while (await session.MoveNextAsync()) + while (await session.MoveNextAsync().ConfigureAwait(false)) { yield return session.Current; } diff --git a/src/Uno.Extensions.Reactive/Sources/Dynamic/FeedExecution.cs b/src/Uno.Extensions.Reactive/Sources/Dynamic/FeedExecution.cs index f537a354ad..4b1bd36f85 100644 --- a/src/Uno.Extensions.Reactive/Sources/Dynamic/FeedExecution.cs +++ b/src/Uno.Extensions.Reactive/Sources/Dynamic/FeedExecution.cs @@ -12,6 +12,11 @@ namespace Uno.Extensions.Reactive.Sources; internal abstract class FeedExecution : IAsyncDisposable { private static readonly AsyncLocal _current = new(); + + /// + /// Gets the current execution if any. + /// This is not null when used within a method, and null otherwise. + /// public static FeedExecution? Current => _current.Value; internal static CurrentSubscription SetCurrent(FeedExecution execution) diff --git a/src/Uno.Extensions.Reactive/Sources/Dynamic/FeedSession.T.Execution.cs b/src/Uno.Extensions.Reactive/Sources/Dynamic/FeedSession.T.Execution.cs index 3f66f265dc..b98ed887ee 100644 --- a/src/Uno.Extensions.Reactive/Sources/Dynamic/FeedSession.T.Execution.cs +++ b/src/Uno.Extensions.Reactive/Sources/Dynamic/FeedSession.T.Execution.cs @@ -101,13 +101,13 @@ private async Task EnableCore() ValueTask> task = default; try { - await NotifyBegin(); + await NotifyBegin().ConfigureAwait(false); task = _session._mainAsyncAction(Token); } catch (OperationCanceledException) when (Token.IsCancellationRequested) { - await NotifyEnd(FeedExecutionResult.Cancelled); + await NotifyEnd(FeedExecutionResult.Cancelled).ConfigureAwait(false); lock (StateGate) { @@ -131,7 +131,7 @@ private async Task EnableCore() } catch (Exception error) { - await NotifyEnd(FeedExecutionResult.Failed); + await NotifyEnd(FeedExecutionResult.Failed).ConfigureAwait(false); lock (StateGate) { @@ -173,7 +173,7 @@ private async Task EnableCore() if (Token.IsCancellationRequested) { - await NotifyEnd(FeedExecutionResult.Cancelled); + await NotifyEnd(FeedExecutionResult.Cancelled).ConfigureAwait(false); lock (StateGate) { // Even if we have been cancelled (because a new execution request has been queued), @@ -224,7 +224,7 @@ private async Task EnableCore() { var data = await task.ConfigureAwait(false); - await NotifyEnd(FeedExecutionResult.Success); + await NotifyEnd(FeedExecutionResult.Success).ConfigureAwait(false); lock (StateGate) { @@ -244,7 +244,7 @@ private async Task EnableCore() } catch (OperationCanceledException) when (Token.IsCancellationRequested) { - await NotifyEnd(FeedExecutionResult.Cancelled); + await NotifyEnd(FeedExecutionResult.Cancelled).ConfigureAwait(false); lock (StateGate) { @@ -256,7 +256,7 @@ private async Task EnableCore() } catch (Exception error) { - await NotifyEnd(FeedExecutionResult.Failed); + await NotifyEnd(FeedExecutionResult.Failed).ConfigureAwait(false); lock (StateGate) { @@ -292,7 +292,7 @@ private async ValueTask NotifyBegin() { try { - await dependency.OnExecuting(this, Token); + await dependency.OnExecuting(this, Token).ConfigureAwait(false); } catch (Exception e) { @@ -308,7 +308,7 @@ private async ValueTask NotifyEnd(FeedExecutionResult result) try { // Note: No CT for the end notification (the current Token might already be cancelled). - await dependency.OnExecuted(this, result, default); + await dependency.OnExecuted(this, result, default).ConfigureAwait(false); } catch (Exception e) { diff --git a/src/Uno.Extensions.Reactive/Utils/AsyncEnumerables/ForEachRunner.cs b/src/Uno.Extensions.Reactive/Utils/AsyncEnumerables/ForEachRunner.cs index 467d5eec86..810ec183e7 100644 --- a/src/Uno.Extensions.Reactive/Utils/AsyncEnumerables/ForEachRunner.cs +++ b/src/Uno.Extensions.Reactive/Utils/AsyncEnumerables/ForEachRunner.cs @@ -42,7 +42,7 @@ private async void EnsureEnumeration() try { - await _enumeratorProvider().ForEachAwaitAsync(async item => await _asyncAction(item, _enumerationToken.Token), _enumerationToken.Token); + await _enumeratorProvider().ForEachAwaitAsync(async item => await _asyncAction(item, _enumerationToken.Token).ConfigureAwait(false), _enumerationToken.Token).ConfigureAwait(false); } catch (OperationCanceledException) { diff --git a/src/Uno.Extensions.Reactive/Utils/AsyncEnumerables/RefCountedForEachRunner.cs b/src/Uno.Extensions.Reactive/Utils/AsyncEnumerables/RefCountedForEachRunner.cs index 7adee59878..5c1fc75aa8 100644 --- a/src/Uno.Extensions.Reactive/Utils/AsyncEnumerables/RefCountedForEachRunner.cs +++ b/src/Uno.Extensions.Reactive/Utils/AsyncEnumerables/RefCountedForEachRunner.cs @@ -112,7 +112,7 @@ private async Task EnumerateInner(CancellationToken ct) try { - await _enumeratorProvider().ForEachAwaitAsync(async item => await _asyncAction(item, ct), ct); + await _enumeratorProvider().ForEachAwaitAsync(async item => await _asyncAction(item, ct).ConfigureAwait(false), ct).ConfigureAwait(false); } catch (OperationCanceledException) { diff --git a/src/Uno.Extensions.Reactive/Utils/AsyncOperationManager/LastWinsAsyncOperationManager.cs b/src/Uno.Extensions.Reactive/Utils/AsyncOperationManager/LastWinsAsyncOperationManager.cs index 6563c2cdd9..c873d6c544 100644 --- a/src/Uno.Extensions.Reactive/Utils/AsyncOperationManager/LastWinsAsyncOperationManager.cs +++ b/src/Uno.Extensions.Reactive/Utils/AsyncOperationManager/LastWinsAsyncOperationManager.cs @@ -76,7 +76,7 @@ private async void Run(AsyncAction operation, CancellationToken ct) { try { - await operation(ct); + await operation(ct).ConfigureAwait(false); } catch (OperationCanceledException) when (ct.IsCancellationRequested) { diff --git a/src/Uno.Extensions.Reactive/Utils/AsyncOperationManager/SequentialAsyncOperationsManager.cs b/src/Uno.Extensions.Reactive/Utils/AsyncOperationManager/SequentialAsyncOperationsManager.cs index 31b166a9f8..c0df19e208 100644 --- a/src/Uno.Extensions.Reactive/Utils/AsyncOperationManager/SequentialAsyncOperationsManager.cs +++ b/src/Uno.Extensions.Reactive/Utils/AsyncOperationManager/SequentialAsyncOperationsManager.cs @@ -116,7 +116,7 @@ private async Task Dequeue() try { - await operation(_ct.Token); + await operation(_ct.Token).ConfigureAwait(false); } catch (OperationCanceledException) when (_ct.IsCancellationRequested) { diff --git a/src/Uno.Extensions.Reactive/Utils/Disposables/CompositeAsyncDisposable.cs b/src/Uno.Extensions.Reactive/Utils/Disposables/CompositeAsyncDisposable.cs index 0430166d30..bcce2d88ac 100644 --- a/src/Uno.Extensions.Reactive/Utils/Disposables/CompositeAsyncDisposable.cs +++ b/src/Uno.Extensions.Reactive/Utils/Disposables/CompositeAsyncDisposable.cs @@ -52,7 +52,7 @@ public async ValueTask RemoveAsync(IAsyncDisposable item) var (isRemoved, asyncDispose) = RemoveCore(item); if (isRemoved) { - await asyncDispose; + await asyncDispose.ConfigureAwait(false); return true; } else diff --git a/src/Uno.Extensions.Reactive/Utils/OptionExtensions.cs b/src/Uno.Extensions.Reactive/Utils/OptionExtensions.cs index 856b1abe07..033c5721b1 100644 --- a/src/Uno.Extensions.Reactive/Utils/OptionExtensions.cs +++ b/src/Uno.Extensions.Reactive/Utils/OptionExtensions.cs @@ -40,16 +40,16 @@ public static Func, Option> SomeOrNone(this Func< #region AsyncFunc [MethodImpl(MethodImplOptions.AggressiveInlining)] public static AsyncFunc> SomeOrNoneWhenNotNull(this AsyncFunc func) - => async ct => Option.SomeOrNone(await func(ct)); + => async ct => Option.SomeOrNone(await func(ct).ConfigureAwait(false)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static AsyncFunc> SomeOrNone(this AsyncFunc func) - => async ct => Option.SomeOrNone(await func(ct)); + => async ct => Option.SomeOrNone(await func(ct).ConfigureAwait(false)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static AsyncFunc> SomeOrNone(this AsyncFunc func) where T : struct - => async ct => Option.SomeOrNone(await func(ct)); + => async ct => Option.SomeOrNone(await func(ct).ConfigureAwait(false)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static AsyncFunc, Option> SomeOrNoneWhenNotNull(this AsyncFunc func)