Skip to content

Conversation

@nvborisenko
Copy link
Member

@nvborisenko nvborisenko commented Dec 6, 2025

User description

It was mistake previously. We introduced BrowsingContext events at core level.

Before:

// it was fired only and only when we know event came from specific context
await bidi.Network.OnBeforeRequestAsync(e => ConsoleWriteLine, new() {Contexts = ["123"]}); 

After:

// now it doesn't matter, events handler is in global context, always
await bidi.Network.OnBeforeRequestAsync(e => ConsoleWriteline, new() .........);

But:

// this one is still context aware!!!
await context.Network.OnBeforeRequestAsync(e => Console.WriteLine);

🔗 Related Issues

Related to #16095

💥 What does this PR do?

Removes limitation from events filtering, allowing any events to be fired in scope of bidi instance.

🔄 Types of changes

  • Bug fix (backwards compatible)

PR Type

Bug fix


Description

  • Remove browsing context filtering at core BiDi level

  • Move context filtering to BrowsingContext module wrappers

  • Simplify event handler architecture by removing context storage

  • Update event args inheritance to use base EventArgs class


Diagram Walkthrough

flowchart LR
  A["BiDi Core Events"] -->|"No context filtering"| B["Event Handlers"]
  B -->|"All events fired"| C["BrowsingContext Wrappers"]
  C -->|"Filter by context"| D["Context-specific handlers"]
Loading

File Walkthrough

Relevant files
Bug fix
1 files
Broker.cs
Remove context filtering logic from event processing         
+3/-13   
Refactoring
10 files
EventHandler.cs
Remove contexts parameter from event handler classes         
+5/-8     
EventArgs.cs
Remove BrowsingContextEventArgs base class definition       
+0/-3     
BrowsingContextInfo.cs
Change inheritance from BrowsingContextEventArgs to EventArgs
+1/-1     
DownloadEndEventArgs.cs
Change inheritance from BrowsingContextEventArgs to EventArgs
+1/-1     
DownloadWillBeginEventArgs.cs
Change inheritance from BrowsingContextEventArgs to EventArgs
+1/-1     
HistoryUpdatedEventArgs.cs
Change inheritance from BrowsingContextEventArgs to EventArgs
+1/-1     
NavigationInfo.cs
Change inheritance from BrowsingContextEventArgs to EventArgs
+1/-1     
UserPromptClosedEventArgs.cs
Change inheritance from BrowsingContextEventArgs to EventArgs
+1/-1     
UserPromptOpenedEventArgs.cs
Change inheritance from BrowsingContextEventArgs to EventArgs
+1/-1     
BaseParametersEventArgs.cs
Change inheritance from BrowsingContextEventArgs to EventArgs
+1/-1     
Enhancement
1 files
BrowsingContextNetworkModule.cs
Add context filtering to network event subscriptions         
+70/-10 
Cleanup
1 files
BrowsingContextScriptModule.cs
Remove unused import statement                                                     
+0/-1     

@selenium-ci selenium-ci added the C-dotnet .NET Bindings label Dec 6, 2025
@qodo-code-review
Copy link
Contributor

qodo-code-review bot commented Dec 6, 2025

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
🟢
No security concerns identified No security vulnerabilities detected by AI analysis. Human verification advised for critical code.
Ticket Compliance
🟡
🎫 #16095
🟢 Decide on scoped event handlers (remove or keep).
Use normal types as event args (inheritance cleanup).
🔴 Move or expose BiDi AsBiDiAsync() extension on AnyDriver/IWebDriver so BiDi instance
lifecycle ties to driver.
Make hidden methods like AddIntercept() public and accessible.
Revisit InterceptRequestAsync and related APIs; provide ergonomic extensions and move
helpers to dedicated namespace using .NET 10 extension capabilities.
Use EmptyResult instead of void as return type across methods.
Remove overengineered Result types (e.g., IReadOnlyList implementations) and odd JSON
converters; rely on extensions like .GetTreeAsync().AsContexts().
Ensure commands return exact types rather than wrapper Result objects.
Make command options immutable so options objects are constructed once and not mutable.
Remove stateful JSON converters that depend on a BiDi object.
Catch-all: consider anything else to finalize public API and prevent future breaking
changes.
None
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status:
Event logging: The new context-filtering wrappers invoke handlers based on context but do not add or
reference any audit logging to record critical network events being handled.

Referred Code
public Task<Subscription> OnBeforeRequestSentAsync(Func<BeforeRequestSentEventArgs, Task> handler, ContextSubscriptionOptions? options = null)
{
    return networkModule.OnBeforeRequestSentAsync(async e =>
    {
        if (context.Equals(e.Context))
        {
            await handler(e).ConfigureAwait(false);
        }
    }, options.WithContext(context));
}

public Task<Subscription> OnBeforeRequestSentAsync(Action<BeforeRequestSentEventArgs> handler, ContextSubscriptionOptions? options = null)
{
    return networkModule.OnBeforeRequestSentAsync(e =>
    {
        if (context.Equals(e.Context))
        {
            handler(e);
        }
    }, options.WithContext(context));
}


 ... (clipped 88 lines)

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status:
Missing guards: The event dispatch loop now invokes all handlers unconditionally without context checks
and lacks try/catch around handler execution, risking unhandled exceptions disrupting
event processing.

Referred Code
if (eventHandlers is not null)
{
    foreach (var handler in eventHandlers.ToArray()) // copy handlers avoiding modified collection while iterating
    {
        var args = result.Params;

        args.BiDi = _bidi;

        await handler.InvokeAsync(args).ConfigureAwait(false);
    }

Learn more about managing compliance generic rules or creating your own custom rules

  • Update
Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

@qodo-code-review
Copy link
Contributor

qodo-code-review bot commented Dec 6, 2025

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
High-level
Consider performance of high-frequency events

The change moves context filtering from a central broker to individual lambda
wrappers for each subscription. This could cause performance issues for
high-frequency events, as every event will now trigger checks across all
subscriptions.

Examples:

dotnet/src/webdriver/BiDi/Broker.cs [109-116]
                        foreach (var handler in eventHandlers.ToArray()) // copy handlers avoiding modified collection while iterating
                        {
                            var args = result.Params;

                            args.BiDi = _bidi;

                            await handler.InvokeAsync(args).ConfigureAwait(false);
                        }
dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContextNetworkModule.cs [94-100]
        return networkModule.OnBeforeRequestSentAsync(async e =>
        {
            if (context.Equals(e.Context))
            {
                await handler(e).ConfigureAwait(false);
            }
        }, options.WithContext(context));

Solution Walkthrough:

Before:

// In Broker.cs
private async Task ProcessEventsAwaiterAsync()
{
    // ...
    foreach (var handler in eventHandlers.ToArray())
    {
        // ...
        // handle browsing context subscriber
        if (handler.Contexts is not null && args is BrowsingContextEventArgs browsingContextEventArgs && handler.Contexts.Contains(browsingContextEventArgs.Context))
        {
            await handler.InvokeAsync(args).ConfigureAwait(false);
        }
        // handle only session subscriber
        else if (handler.Contexts is null)
        {
            await handler.InvokeAsync(args).ConfigureAwait(false);
        }
    }
}

After:

// In Broker.cs
private async Task ProcessEventsAwaiterAsync()
{
    // ...
    foreach (var handler in eventHandlers.ToArray())
    {
        // No more context filtering here.
        await handler.InvokeAsync(args).ConfigureAwait(false);
    }
}

// In BrowsingContextNetworkModule.cs
public Task<Subscription> OnBeforeRequestSentAsync(Func<BeforeRequestSentEventArgs, Task> handler, ...)
{
    return networkModule.OnBeforeRequestSentAsync(async e =>
    {
        // Filtering is done in a wrapper for each subscriber.
        if (context.Equals(e.Context))
        {
            await handler(e).ConfigureAwait(false);
        }
    }, ...);
}
Suggestion importance[1-10]: 7

__

Why: This is a valid and insightful observation about the performance implications of the architectural change, correctly identifying that invoking all handlers for every event could be a bottleneck for high-frequency events.

Medium
Learned
best practice
Deduplicate context-filtering logic

Factor the repeated context-filtering lambda into a private helper to avoid
duplication across all event registration methods.

dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContextNetworkModule.cs [94-100]

-return networkModule.OnBeforeRequestSentAsync(async e =>
-{
-    if (context.Equals(e.Context))
-    {
-        await handler(e).ConfigureAwait(false);
-    }
-}, options.WithContext(context));
+return networkModule.OnBeforeRequestSentAsync(FilterByContext(handler), options.WithContext(context));
 
+private Func<BeforeRequestSentEventArgs, Task> FilterByContext(Func<BeforeRequestSentEventArgs, Task> handler) =>
+    async e => { if (context.Equals(e.Context)) await handler(e).ConfigureAwait(false); };
+
  • Apply / Chat
Suggestion importance[1-10]: 6

__

Why:
Relevant best practice - Replace ad-hoc duplication with shared helpers/utilities to reduce repetition and centralize logic.

Low
  • Update

@nvborisenko nvborisenko merged commit 87fef04 into SeleniumHQ:trunk Dec 6, 2025
10 checks passed
@nvborisenko nvborisenko deleted the bidi-new-events-scoping branch December 6, 2025 19:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants