Table of Contents

Class BiDiDriver

Namespace
WebDriverBiDi
Assembly
WebDriverBiDi.dll

Object containing commands to drive a browser using the WebDriver BiDi protocol.

public class BiDiDriver : IBiDiDriverLifecycleManager, IAsyncDisposable, IBiDiModuleHost, IBiDiDriverConfiguration, IBiDiDriverEvents, IEventObserverErrorReporter
Inheritance
BiDiDriver
Implements
Inherited Members

Remarks

Thread Safety: This class is thread-safe for concurrent command execution. ExecuteCommandAsync<T>(CommandParameters<T>, TimeSpan?, CancellationToken) and module command methods may be called concurrently from multiple threads. Configuration operations (RegisterModule(Module), RegisterEvent<T>(string, Func<EventInfo<T>, Task>), RegisterTypeInfoResolverAsync(IJsonTypeInfoResolver, CancellationToken)) must complete before StartAsync(string, CancellationToken) is called and are serialized via an internal lock.

Interface Design: This class implements five focused interfaces (IBiDiModuleHost, IBiDiDriverConfiguration, IBiDiDriverLifecycleManager, IBiDiDriverEvents, IEventObserverErrorReporter) for advanced framework, testing, and extensibility scenarios. Most application code should use BiDiDriver directly and ignore these interfaces. See the Core Concepts documentation for guidance on when each interface applies.

Constructors

BiDiDriver()

Initializes a new instance of the BiDiDriver class.

public BiDiDriver()

BiDiDriver(TimeSpan)

Initializes a new instance of the BiDiDriver class with the specified default command wait timeout.

public BiDiDriver(TimeSpan defaultCommandWaitTimeout)

Parameters

defaultCommandWaitTimeout TimeSpan

The default timeout to wait for a command to complete.

BiDiDriver(TimeSpan, Transport)

Initializes a new instance of the BiDiDriver class with the specified default command wait timeout and Transport.

public BiDiDriver(TimeSpan defaultCommandWaitTimeout, Transport transport)

Parameters

defaultCommandWaitTimeout TimeSpan

The default timeout to wait for a command to complete. Must be non-negative and no greater than the maximum timer duration supported by the runtime (about 49.7 days; about 24.8 days on .NET Framework), or InfiniteTimeSpan to wait indefinitely.

transport Transport

The protocol transport object used to communicate with the browser.

Remarks

This constructor is used when you need to provide a custom Transport instance, typically for advanced scenarios such as:

  • Using a custom Connection implementation with specific timeout configurations
  • Sharing a transport across multiple driver instances (not recommended for typical usage)
  • Integrating with specialized connection management frameworks

Ownership: a driver takes ownership of the transport passed to it. DisposeAsync() disposes the transport, which in turn disposes its Connection. A transport shared between drivers is therefore torn down for every one of them as soon as the first is disposed, so a shared transport must outlive all of its drivers, or the drivers must not be disposed. Additionally, a transport must be disconnected when passed to the driver, as the driver must register modules and events with the transport, and cannot do so once a connection has been started.

Most users should use the simpler BiDiDriver(TimeSpan) constructor instead, which creates a default WebSocket-based transport automatically.

Exceptions

ArgumentNullException

Thrown when transport is null.

ArgumentOutOfRangeException

Thrown when defaultCommandWaitTimeout is negative (other than InfiniteTimeSpan) or exceeds the maximum supported timer duration.

ArgumentException

Thrown when the State property of the supplied transport is other than Disconnected.

BiDiDriver(Transport)

Initializes a new instance of the BiDiDriver class with the specified Transport.

public BiDiDriver(Transport transport)

Parameters

transport Transport

The protocol transport object used to communicate with the browser.

Remarks

Using this constructor will use the value of DefaultCommandWaitTimeout as the timeout for commands with this driver.

Ownership: a driver takes ownership of the transport passed to it. DisposeAsync() disposes the transport, which in turn disposes its Connection. A transport shared between drivers is therefore torn down for every one of them as soon as the first is disposed, so a shared transport must outlive all of its drivers, or the drivers must not be disposed. Additionally, a transport must be disconnected when passed to the driver, as the driver must register modules and events with the transport, and cannot do so once a connection has been started.

Exceptions

ArgumentNullException

Thrown when transport is null.

ArgumentException

Thrown when the State property of the supplied transport is other than Disconnected.

Fields

DefaultCommandWaitTimeout

Gets the default command timeout if a timeout is not specified in the constructor.

public static readonly TimeSpan DefaultCommandWaitTimeout

Field Value

TimeSpan

LoggerComponentName

Gets the component name for this class to use in log messages.

public const string LoggerComponentName = "BiDiDriver"

Field Value

string

Properties

Bluetooth

Gets the bluetooth module as described in the W3C Web Bluetooth Specification.

public BluetoothModule Bluetooth { get; }

Property Value

BluetoothModule

Browser

Gets the browser module as described in the WebDriver BiDi protocol.

public BrowserModule Browser { get; }

Property Value

BrowserModule

BrowsingContext

Gets the browsingContext module as described in the WebDriver BiDi protocol.

public BrowsingContextModule BrowsingContext { get; }

Property Value

BrowsingContextModule

DefaultCommandTimeout

Gets the default timeout to wait for a command to complete. This timeout is specified in the constructor and is used by the ExecuteCommandAsync<T>(CommandParameters<T>, TimeSpan?, CancellationToken) overloads when a command timeout is not explicitly provided.

public virtual TimeSpan DefaultCommandTimeout { get; }

Property Value

TimeSpan

DigitalCredentials

Gets the digitalCredentials module as described in the W3C Digital Credentials specification.

public DigitalCredentialsModule DigitalCredentials { get; }

Property Value

DigitalCredentialsModule

Emulation

Gets the emulation module as described in the WebDriver BiDi protocol.

public EmulationModule Emulation { get; }

Property Value

EmulationModule

Input

Gets the input module as described in the WebDriver BiDi protocol.

public InputModule Input { get; }

Property Value

InputModule

IsDisposed

Gets a value indicating whether this driver is disposed. Use this property to ensure thread-safe operations for checking disposal state.

protected bool IsDisposed { get; }

Property Value

bool

IsStarted

Gets a value indicating whether the driver has started communication with the remote end of the WebDriver BiDi protocol.

public virtual bool IsStarted { get; }

Property Value

bool

Remarks

This property returns true after StartAsync(string, CancellationToken) completes successfully and remains true until StopAsync(CancellationToken) is called or the connection is lost.

The value reflects the state the transport itself tracks across its own connect and disconnect operations; it is not a live query of the underlying IsActive. The two can therefore disagree briefly: a connection that reaches end-of-file, for example, reports itself inactive before the transport's disconnection handling has run and cleared this value.

Use this property to check driver state before executing commands or during cleanup operations.

Important timing restriction: Modules (RegisterModule(Module)), custom events (RegisterEvent<T>(string, Func<EventInfo<T>, Task>)), and type info resolvers (RegisterTypeInfoResolverAsync(IJsonTypeInfoResolver, CancellationToken)) must be registered before calling StartAsync(string, CancellationToken); attempting any of these after the driver has started throws an InvalidOperationException. Adding observers to an ObservableEvent<T> with AddObserver(Func<T, Task>, ObservableEventHandlerOptions, string) is not restricted and may be done at any time, before or after the driver has started.

Log

Gets the log module as described in the WebDriver BiDi protocol.

public LogModule Log { get; }

Property Value

LogModule

Network

Gets the network module as described in the WebDriver BiDi protocol.

public NetworkModule Network { get; }

Property Value

NetworkModule

OnConnectionLost

Gets an observable event that notifies when an established connection ends without the client stopping it: the remote end closed it, as when the browser exits, or it failed.

public ObservableEvent<ConnectionLostEventArgs> OnConnectionLost { get; }

Property Value

ObservableEvent<ConnectionLostEventArgs>

Remarks

It is raised after the events received before the loss, once the session has been torn down: IsStarted is false and commands in flight have failed. Starting the driver again from inside an observer waits for the loop that runs it, as for any event observer, so restart from outside the observer, or from one added with RunHandlerAsynchronously. It is not raised when the driver is stopped, nor for a connection lost while it is being established, which fails StartAsync(string, CancellationToken) instead.

OnEventHandlerErrorOccurred

Gets an observable event that notifies when an error occurs in an observer of an observable event.

public ObservableEvent<EventHandlerErrorOccurredEventArgs> OnEventHandlerErrorOccurred { get; }

Property Value

ObservableEvent<EventHandlerErrorOccurredEventArgs>

Remarks

This event is for diagnostic and observability purposes, and does not prevent the propagation of the error back to the Transport class.

OnEventReceived

Gets an observable event that notifies when a protocol event is received from protocol transport.

public ObservableEvent<EventReceivedEventArgs> OnEventReceived { get; }

Property Value

ObservableEvent<EventReceivedEventArgs>

OnLogMessage

Gets an observable event that notifies when a log message is emitted by this driver.

public ObservableEvent<LogMessageEventArgs> OnLogMessage { get; }

Property Value

ObservableEvent<LogMessageEventArgs>

OnUnexpectedErrorReceived

Gets an observable event that notifies when a protocol error is received from protocol transport.

public ObservableEvent<ErrorReceivedEventArgs> OnUnexpectedErrorReceived { get; }

Property Value

ObservableEvent<ErrorReceivedEventArgs>

OnUnknownMessageReceived

Gets an observable event that notifies when an unknown message is received from protocol transport.

public ObservableEvent<UnknownMessageReceivedEventArgs> OnUnknownMessageReceived { get; }

Property Value

ObservableEvent<UnknownMessageReceivedEventArgs>

Permissions

Gets the permissions module as described in the W3C Permissions Specification.

public PermissionsModule Permissions { get; }

Property Value

PermissionsModule

Script

Gets the script module as described in the WebDriver BiDi protocol.

public ScriptModule Script { get; }

Property Value

ScriptModule

Session

Gets the session module as described in the WebDriver BiDi protocol.

public SessionModule Session { get; }

Property Value

SessionModule

Speculation

Gets the speculation module as described in the W3C Community Group Prerendering specification.

public SpeculationModule Speculation { get; }

Property Value

SpeculationModule

Storage

Gets the storage module as described in the WebDriver BiDi protocol.

public StorageModule Storage { get; }

Property Value

StorageModule

TransportConfiguration

Gets the tunable settings of the transport this driver communicates through.

public virtual ITransportConfiguration TransportConfiguration { get; }

Property Value

ITransportConfiguration

Remarks

The settings live on the transport, and this property is how a driver created with BiDiDriver() or BiDiDriver(TimeSpan) reaches them: those constructors create the transport themselves, so there is no other reference to it. A driver constructed with BiDiDriver(TimeSpan, Transport) or BiDiDriver(Transport) may equally use the transport it was handed.

Setting a value here is the same as setting it on the transport; there is no driver-level copy.

TransportDiagnostics

Gets the observable state of the transport this driver communicates through.

public virtual ITransportDiagnostics TransportDiagnostics { get; }

Property Value

ITransportDiagnostics

Remarks

Every value is a snapshot that may be stale by the time the caller observes it, and none of them throws at any point of the driver's lifecycle, so they are safe to poll. IsStarted answers the common question more directly; use State when the states it collapses into false need to be told apart.

UserAgentClientHints

Gets the user agent client hints module as described in the W3C Community Group User Agent Client Hints specification.

public UserAgentClientHintsModule UserAgentClientHints { get; }

Property Value

UserAgentClientHintsModule

WebExtension

Gets the web extension module as described in the WebDriver BiDi protocol.

public WebExtensionModule WebExtension { get; }

Property Value

WebExtensionModule

Methods

DisposeAsync()

Asynchronously releases the resources used by this driver instance.

public ValueTask DisposeAsync()

Returns

ValueTask

A task that represents the asynchronous dispose operation.

Remarks

If any TransportErrorBehavior is Collect, the collected exceptions are thrown only by StopAsync(CancellationToken). DisposeAsync() catches and logs them at Warn level and does not rethrow. Call StopAsync(CancellationToken) first to observe them.

DisposeAsyncCore()

Asynchronously releases the resources used by this driver instance. Override this method in derived classes to add custom cleanup logic.

protected virtual ValueTask DisposeAsyncCore()

Returns

ValueTask

A task that represents the asynchronous dispose operation.

ExecuteCommandAsync<T>(CommandParameters, TimeSpan?, CancellationToken)

Asynchronously sends a command to the remote end of the WebDriver BiDi protocol and waits for a response.

public virtual Task<T> ExecuteCommandAsync<T>(CommandParameters commandParameters, TimeSpan? commandTimeout = null, CancellationToken cancellationToken = default) where T : CommandResult

Parameters

commandParameters CommandParameters

The object containing settings for the command, including parameters.

commandTimeout TimeSpan?

The timeout to wait for the command to complete, or null to use DefaultCommandTimeout. Must be non-negative and no greater than the maximum timer duration supported by the runtime, or InfiniteTimeSpan to wait indefinitely.

cancellationToken CancellationToken

A cancellation token used to propagate notification that the operation should be canceled. Defaults to None, if unspecified.

Returns

Task<T>

The task object representing the asynchronous operation.

Type Parameters

T

The expected type of the result of the command.

Exceptions

ArgumentOutOfRangeException

Thrown when commandTimeout is negative (other than InfiniteTimeSpan) or exceeds the maximum supported timer duration.

WebDriverBiDiCommandException

Thrown if an error occurs during the execution of the command.

WebDriverBiDiSerializationException

Thrown if the command parameters cannot be serialized, or the response cannot be deserialized.

WebDriverBiDiTimeoutException

Thrown if the command execution exceeds the specified timeout.

WebDriverBiDiConnectionException

Thrown if the connection is interrupted during command execution.

WebDriverBiDiException

Thrown if the command is cancelled, returns a null value, or does not return a result of the correct object type.

OperationCanceledException

Thrown when cancellationToken is canceled.

ObjectDisposedException

Thrown when attempting to call this method after the driver is disposed.

ArgumentNullException

Thrown when commandParameters is null.

ExecuteCommandAsync<T>(CommandParameters<T>, TimeSpan?, CancellationToken)

Asynchronously sends a command to the remote end of the WebDriver BiDi protocol and waits for a response. The result type is inferred from the command parameters.

public virtual Task<T> ExecuteCommandAsync<T>(CommandParameters<T> commandParameters, TimeSpan? commandTimeout = null, CancellationToken cancellationToken = default) where T : CommandResult

Parameters

commandParameters CommandParameters<T>

The object containing settings for the command, including parameters.

commandTimeout TimeSpan?

The timeout to wait for the command to complete, or null to use DefaultCommandTimeout. Must be non-negative and no greater than the maximum timer duration supported by the runtime, or InfiniteTimeSpan to wait indefinitely.

cancellationToken CancellationToken

A cancellation token used to propagate notification that the operation should be canceled. Defaults to None, if unspecified.

Returns

Task<T>

The task object representing the asynchronous operation.

Type Parameters

T

The expected type of the result of the command.

Exceptions

ArgumentOutOfRangeException

Thrown when commandTimeout is negative (other than InfiniteTimeSpan) or exceeds the maximum supported timer duration.

WebDriverBiDiCommandException

Thrown if an error occurs during the execution of the command.

WebDriverBiDiSerializationException

Thrown if the command parameters cannot be serialized, or the response cannot be deserialized.

WebDriverBiDiTimeoutException

Thrown if the command execution exceeds the specified timeout.

WebDriverBiDiConnectionException

Thrown if the connection is interrupted during command execution.

WebDriverBiDiException

Thrown if the command is cancelled, returns a null value, or does not return a result of the correct object type.

OperationCanceledException

Thrown when cancellationToken is canceled.

ObjectDisposedException

Thrown when attempting to call this method after the driver is disposed.

ArgumentNullException

Thrown when commandParameters is null.

GetModule<T>(string)

Gets a module from the set of registered modules for this driver.

public virtual T GetModule<T>(string moduleName) where T : Module

Parameters

moduleName string

The name of the module to return.

Returns

T

The protocol module object.

Type Parameters

T

A module object which is a subclass of Module.

Exceptions

ArgumentException

Thrown when the specified module name is not registered with this driver, or when the module name is null or empty.

InvalidCastException

Thrown when the registered module object is not of the expected type.

ObjectDisposedException

Thrown when attempting to call this method after the driver is disposed.

IsLogLevelEnabled(WebDriverBiDiLogLevel)

Gets a value indicating whether a message at the given level would be raised on OnLogMessage, so that a caller can avoid building a message that would be discarded.

public bool IsLogLevelEnabled(WebDriverBiDiLogLevel level)

Parameters

level WebDriverBiDiLogLevel

The WebDriverBiDiLogLevel of the message the caller would raise.

Returns

bool

true if such a message would be raised; otherwise, false.

Remarks

A message is raised only when its level is at or above LogLevel and OnLogMessage has at least one observer. IsLogLevelEnabled(WebDriverBiDiLogLevel) and IsLogLevelEnabled(WebDriverBiDiLogLevel) answer the same question for their own layer. Off is never enabled. It selects "no messages at all" when assigned to LogLevel, and is not a level a message can carry; without the explicit test it would compare as enabled against every setting, because it is the highest value.

LogAsync(string, WebDriverBiDiLogLevel)

Asynchronously raises a logging event at the specified log level.

protected Task LogAsync(string message, WebDriverBiDiLogLevel logLevel)

Parameters

message string

The log message to raise in the event.

logLevel WebDriverBiDiLogLevel

The WebDriverBiDiLogLevel at which to raise the event.

Returns

Task

The task object representing the asynchronous operation.

Remarks

A message below LogLevel is discarded rather than raised.

This method never throws for a failure in an observer of OnLogMessage; such a failure is routed through the observer-error pipeline, where it is governed by EventHandlerExceptionBehavior.

RegisterEvent<T>(string, Func<EventInfo<T>, Task>)

Registers an event to be raised by the remote end of the WebDriver BiDi protocol.

public virtual void RegisterEvent<T>(string eventName, Func<EventInfo<T>, Task> eventInvoker)

Parameters

eventName string

The name of the event to raise.

eventInvoker Func<EventInfo<T>, Task>

The delegate taking a single parameter of type T used to invoke the event.

Type Parameters

T

The type of data that will be raised by the event.

Remarks

The driver's constructor registers the events of the built-in modules without calling this method, so an override observes only registrations made after the driver has been constructed, such as those of a custom module passed to RegisterModule(Module).

Exceptions

ArgumentException

Thrown when the specified event name is already registered with this driver, or when the event name is null or empty.

ArgumentNullException

Thrown when the event invoker argument is null.

ObjectDisposedException

Thrown when attempting to call this method after the driver is disposed.

InvalidOperationException

Thrown when attempting to call this method after the driver has been started.

RegisterModule(Module)

Registers a module for use with this driver.

public virtual void RegisterModule(Module module)

Parameters

module Module

The module object.

Remarks

Critical timing restriction: Modules must be registered before calling StartAsync(string, CancellationToken). Once the driver has started, module registration is locked to prevent race conditions with event handling.

Thread safety: This method is thread-safe and can be safely called from multiple threads concurrently. Two locks cooperate to make that so. A registration lock serializes concurrent registrations with one another, and the transport tests its own lifecycle state and performs the registration under the same lock it uses to publish the start of a connect. A registration therefore either completes in full while the transport is still idle, or is rejected because it is not; it cannot land part-way through a StartAsync(string, CancellationToken) running on another thread. The check is against the transport's state, not IsStarted: registration is rejected once the transport has left Disconnected, which is as soon as a connect is in flight, and IsStarted is still false at that point.

This method is used for registering custom modules that extend the WebDriver BiDi protocol. All standard modules (Browser, BrowsingContext, Script, Network, etc.) are registered automatically during driver construction and do not need explicit registration.

The driver's constructor registers the built-in modules without calling this method, so an override observes only registrations made after the driver has been constructed.

Example usage:

BiDiDriver driver = new BiDiDriver(TimeSpan.FromSeconds(30));
driver.RegisterModule(new CustomModule(driver));  // Must be before StartAsync
await driver.StartAsync(webSocketUrl);

Exceptions

ArgumentException

Thrown when attempting to register a module with a name that has already been registered.

ArgumentNullException

Thrown when the module argument is null.

ObjectDisposedException

Thrown when attempting to call this method after the driver is disposed.

InvalidOperationException

Thrown when attempting to call this method after the driver has been started.

RegisterTypeInfoResolverAsync(IJsonTypeInfoResolver, CancellationToken)

Registers an additional IJsonTypeInfoResolver for JSON serialization and deserialization. This allows custom types, such as those from user-defined modules, to be serialized in AOT scenarios where reflection-based serialization is unavailable. This method must be called while the driver is not started: before the first call to StartAsync(string, CancellationToken), or after a call to StopAsync(CancellationToken). Resolvers registered earlier remain in effect.

public virtual Task RegisterTypeInfoResolverAsync(IJsonTypeInfoResolver resolver, CancellationToken cancellationToken = default)

Parameters

resolver IJsonTypeInfoResolver

The type info resolver to add.

cancellationToken CancellationToken

A cancellation token that can be used to cancel the asynchronous operation.

Returns

Task

A Task representing the asynchronous operation.

Exceptions

ArgumentNullException

Thrown when the resolver argument is null.

ObjectDisposedException

Thrown if the driver has been disposed.

InvalidOperationException

Thrown if the driver has already been started.

WebDriverBiDiTimeoutException

Thrown when exclusive access to the transport's connection is not obtained within ConnectionLockTimeout.

OperationCanceledException

Thrown when cancellationToken is canceled.

StartAsync(string, CancellationToken)

Asynchronously starts the communication with the remote end of the WebDriver BiDi protocol.

public virtual Task StartAsync(string connectionString, CancellationToken cancellationToken = default)

Parameters

connectionString string

The connection string used to connect to the remote end. Usually the URL to the WebSocket used to communicate with the remote end.

cancellationToken CancellationToken

A cancellation token used to propagate notification that the operation should be canceled.

Returns

Task

The task object representing the asynchronous operation.

Remarks

Starting begins a new session and clears the errors the previous session accumulated under Collect. Those errors are thrown only by StopAsync(CancellationToken). After a remote disconnect the driver is already stopped (IsStarted is false), so this method proceeds; to observe the errors collected up to the disconnect, call StopAsync(CancellationToken) (which returns promptly and throws them) before starting again. Starting directly discards them.

Exceptions

WebDriverBiDiConnectionException

Thrown when the driver has already been started, or when the underlying Connection refuses to open.

WebDriverBiDiTimeoutException

Thrown when the underlying Connection is not established within its StartupTimeout. The default WebSocket connection retries until that budget is exhausted before reporting the failure this way.

ArgumentException

Thrown by the default WebSocket connection when connectionString is not valid for the connection type. For the default WebSocketConnection, this exception would be thrown when the connection string is not an absolute URI, or when its scheme is neither ws nor wss. A different Connection type, such as PipeConnection, validates its own connection string and may not throw this.

OperationCanceledException

Thrown when cancellationToken is canceled.

ObjectDisposedException

Thrown when attempting to call this method after the driver is disposed.

StopAsync(CancellationToken)

Asynchronously stops the communication with the remote end of the WebDriver BiDi protocol.

public virtual Task StopAsync(CancellationToken cancellationToken = default)

Parameters

cancellationToken CancellationToken

A cancellation token used to propagate notification that the operation should be canceled.

Returns

Task

The task object representing the asynchronous operation.

Exceptions

AggregateException

Thrown when Collect is configured for any error category and one or more errors were collected during the session. The aggregated exceptions describe the collected errors.

WebDriverBiDiTimeoutException

Thrown when exclusive access to the transport's connection is not obtained within ConnectionLockTimeout.

OperationCanceledException

Thrown when cancellationToken is canceled.

See Also