You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This enhancement allows consumers of the API to cancel pending event subscriptions and unsubscriptions, improving responsiveness and resource management in scenarios where operations may need to be aborted.
Added a CancellationToken parameter to all event subscription methods in BrowsingContextModule, including navigation, history, download, context, and user prompt events, allowing callers to cancel subscriptions if needed.
🔄 Types of changes
New feature (non-breaking change which adds functionality and tests!)
Breaking change (fix or feature that would cause existing functionality to change)
PR Type
Enhancement
Description
Add CancellationToken parameter to all BiDi event subscription methods
Enable cancellation of pending event subscriptions across modules
Support cancellation in SubscribeAsync and UnsubscribeAsync operations
Propagate cancellation tokens through broker and module layers
Diagram Walkthrough
flowchart LR
A["Event Subscription Methods"] -->|Add CancellationToken| B["Module Layer"]
B -->|Pass Token| C["Broker.SubscribeAsync"]
C -->|Forward Token| D["SessionModule.SubscribeAsync"]
E["Subscription.UnsubscribeAsync"] -->|Add CancellationToken| F["Broker.UnsubscribeAsync"]
F -->|Forward Token| G["SessionModule.UnsubscribeAsync"]
Loading
File Walkthrough
Relevant files
Enhancement
11 files
Broker.cs
Add cancellation token to subscribe and unsubscribe methods
Consider simplifying the duplicated subscription logic
Refactor the duplicated event subscription logic by having the Action overload call the Func<T, Task> overload. This will remove boilerplate code across multiple modules and improve maintainability.
// In a module like `BrowsingContextModule`publicasyncTask<Subscription>OnNavigationStartedAsync(Func<NavigationInfo,Task>handler,SubscriptionOptions?options=null,CancellationTokencancellationToken=default){returnawaitSubscribeAsync("browsingContext.navigationStarted",handler,options,_jsonContext.NavigationInfo,cancellationToken).ConfigureAwait(false);}publicasyncTask<Subscription>OnNavigationStartedAsync(Action<NavigationInfo>handler,SubscriptionOptions?options=null,CancellationTokencancellationToken=default){returnawaitSubscribeAsync("browsingContext.navigationStarted",handler,options,_jsonContext.NavigationInfo,cancellationToken).ConfigureAwait(false);}// ... this pattern is repeated for many other events
After:
// In a module like `BrowsingContextModule`publicasyncTask<Subscription>OnNavigationStartedAsync(Func<NavigationInfo,Task>handler,SubscriptionOptions?options=null,CancellationTokencancellationToken=default){returnawaitSubscribeAsync("browsingContext.navigationStarted",handler,options,_jsonContext.NavigationInfo,cancellationToken).ConfigureAwait(false);}publicasyncTask<Subscription>OnNavigationStartedAsync(Action<NavigationInfo>handler,SubscriptionOptions?options=null,CancellationTokencancellationToken=default){// Call the Func overload, wrapping the Action.returnawaitOnNavigationStartedAsync(e =>{handler(e);returnTask.CompletedTask;},options,cancellationToken).ConfigureAwait(false);}// ... this pattern is repeated for many other events
Suggestion importance[1-10]: 8
__
Why: The suggestion correctly identifies significant code duplication across multiple modules where Action and Func overloads for event subscriptions are nearly identical, and a refactoring would greatly improve code maintainability.
Medium
General
Pass cancellation token to subscription
Pass the cancellationToken to the Subscription constructor to enable cancellable disposal of subscriptions.
public async Task<Subscription> SubscribeAsync<TEventArgs>(string eventName, EventHandler eventHandler, SubscriptionOptions? options, JsonTypeInfo<TEventArgs> jsonTypeInfo, CancellationToken cancellationToken)
where TEventArgs : EventArgs
{
_eventTypesMap[eventName] = jsonTypeInfo;
var handlers = _eventHandlers.GetOrAdd(eventName, (a) => []);
var subscribeResult = await _bidi.SessionModule.SubscribeAsync([eventName], new() { Contexts = options?.Contexts, UserContexts = options?.UserContexts }, cancellationToken).ConfigureAwait(false);
handlers.Add(eventHandler);
- return new Subscription(subscribeResult.Subscription, this, eventHandler);+ return new Subscription(subscribeResult.Subscription, this, eventHandler, cancellationToken);
}
Apply / Chat
Suggestion importance[1-10]: 7
__
Why: This suggestion correctly identifies a way to improve the cancellation logic by passing the cancellationToken to the Subscription constructor, which enables its use during disposal. This enhances the robustness of the cancellation feature introduced in the PR.
Medium
Possible issue
Postpone state updates until after subscribe
Reorder operations in SubscribeAsync to update internal state like _eventTypesMap and _eventHandlers only after the subscription call successfully completes, preventing state inconsistency on failure or cancellation.
Why: The suggestion correctly points out a potential state inconsistency issue if the SubscribeAsync call fails or is cancelled. Reordering the operations to update internal state only after the remote call succeeds makes the method more robust and atomic.
Low
Swap unsubscribe order for consistency
In UnsubscribeAsync, call the remote unsubscribe method before removing the local event handler to ensure state consistency in case of cancellation or errors.
[To ensure code accuracy, apply this suggestion manually]
Suggestion importance[1-10]: 6
__
Why: This suggestion correctly identifies a potential state inconsistency issue. By performing the remote UnsubscribeAsync call before removing the local event handler, it ensures the local state is only updated upon successful unsubscription, making the operation more robust.
Low
Learned best practice
Make unsubscribe/dispose idempotent
Track an _unsubscribed flag (via Interlocked.Exchange) so UnsubscribeAsync/DisposeAsync are idempotent and safe if called multiple times or concurrently.
public async Task<Subscription> SubscribeAsync<TEventArgs>(string eventName, EventHandler eventHandler, SubscriptionOptions? options, JsonTypeInfo<TEventArgs> jsonTypeInfo, CancellationToken cancellationToken)
where TEventArgs : EventArgs
{
+ if (string.IsNullOrWhiteSpace(eventName))+ {+ throw new ArgumentException("Event name must be provided.", nameof(eventName));+ }++ cancellationToken.ThrowIfCancellationRequested();+
_eventTypesMap[eventName] = jsonTypeInfo;
- var handlers = _eventHandlers.GetOrAdd(eventName, (a) => []);+ var handlers = _eventHandlers.GetOrAdd(eventName, _ => []);- var subscribeResult = await _bidi.SessionModule.SubscribeAsync([eventName], new() { Contexts = options?.Contexts, UserContexts = options?.UserContexts }, cancellationToken).ConfigureAwait(false);+ var subscribeResult = await _bidi.SessionModule+ .SubscribeAsync([eventName], new() { Contexts = options?.Contexts, UserContexts = options?.UserContexts }, cancellationToken)+ .ConfigureAwait(false);
handlers.Add(eventHandler);
return new Subscription(subscribeResult.Subscription, this, eventHandler);
}
Apply / Chat
Suggestion importance[1-10]: 5
__
Why:
Relevant best practice - Add explicit validation and cancellation guards at integration boundaries before mutating internal state or making remote calls.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
User description
This enhancement allows consumers of the API to cancel pending event subscriptions and unsubscriptions, improving responsiveness and resource management in scenarios where operations may need to be aborted.
🔗 Related Issues
Continuation of #16989
💥 What does this PR do?
CancellationTokenparameter to all event subscription methods inBrowsingContextModule, including navigation, history, download, context, and user prompt events, allowing callers to cancel subscriptions if needed.🔄 Types of changes
PR Type
Enhancement
Description
Add
CancellationTokenparameter to all BiDi event subscription methodsEnable cancellation of pending event subscriptions across modules
Support cancellation in
SubscribeAsyncandUnsubscribeAsyncoperationsPropagate cancellation tokens through broker and module layers
Diagram Walkthrough
File Walkthrough
11 files
Add cancellation token to subscribe and unsubscribe methodsPropagate cancellation token through subscription methodsAdd cancellation token to UnsubscribeAsync methodAdd cancellation tokens to all navigation and context eventsAdd cancellation token to file dialog event subscriptionsAdd cancellation token to log entry event subscriptionsAdd cancellation tokens to network event subscriptionsAdd cancellation tokens to network event subscription methodsAdd cancellation token to file dialog event subscriptionsAdd cancellation token to log entry event subscriptionsAdd cancellation tokens to script event subscription methods