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
defaultCommandWaitTimeoutTimeSpanThe 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
defaultCommandWaitTimeoutTimeSpanThe 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.
transportTransportThe 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
transportis null.- ArgumentOutOfRangeException
Thrown when
defaultCommandWaitTimeoutis negative (other than InfiniteTimeSpan) or exceeds the maximum supported timer duration.- ArgumentException
Thrown when the State property of the supplied
transportis other than Disconnected.
BiDiDriver(Transport)
Initializes a new instance of the BiDiDriver class with the specified Transport.
public BiDiDriver(Transport transport)
Parameters
transportTransportThe 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
transportis null.- ArgumentException
Thrown when the State property of the supplied
transportis 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
LoggerComponentName
Gets the component name for this class to use in log messages.
public const string LoggerComponentName = "BiDiDriver"
Field Value
Properties
Bluetooth
Gets the bluetooth module as described in the W3C Web Bluetooth Specification.
public BluetoothModule Bluetooth { get; }
Property Value
Browser
Gets the browser module as described in the WebDriver BiDi protocol.
public BrowserModule Browser { get; }
Property Value
BrowsingContext
Gets the browsingContext module as described in the WebDriver BiDi protocol.
public BrowsingContextModule BrowsingContext { get; }
Property Value
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
DigitalCredentials
Gets the digitalCredentials module as described in the W3C Digital Credentials specification.
public DigitalCredentialsModule DigitalCredentials { get; }
Property Value
Emulation
Gets the emulation module as described in the WebDriver BiDi protocol.
public EmulationModule Emulation { get; }
Property Value
Input
Gets the input module as described in the WebDriver BiDi protocol.
public InputModule Input { get; }
Property Value
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
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
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
Network
Gets the network module as described in the WebDriver BiDi protocol.
public NetworkModule Network { get; }
Property Value
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
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
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
OnLogMessage
Gets an observable event that notifies when a log message is emitted by this driver.
public ObservableEvent<LogMessageEventArgs> OnLogMessage { get; }
Property Value
OnUnexpectedErrorReceived
Gets an observable event that notifies when a protocol error is received from protocol transport.
public ObservableEvent<ErrorReceivedEventArgs> OnUnexpectedErrorReceived { get; }
Property Value
OnUnknownMessageReceived
Gets an observable event that notifies when an unknown message is received from protocol transport.
public ObservableEvent<UnknownMessageReceivedEventArgs> OnUnknownMessageReceived { get; }
Property Value
Permissions
Gets the permissions module as described in the W3C Permissions Specification.
public PermissionsModule Permissions { get; }
Property Value
Script
Gets the script module as described in the WebDriver BiDi protocol.
public ScriptModule Script { get; }
Property Value
Session
Gets the session module as described in the WebDriver BiDi protocol.
public SessionModule Session { get; }
Property Value
Speculation
Gets the speculation module as described in the W3C Community Group Prerendering specification.
public SpeculationModule Speculation { get; }
Property Value
Storage
Gets the storage module as described in the WebDriver BiDi protocol.
public StorageModule Storage { get; }
Property Value
TransportConfiguration
Gets the tunable settings of the transport this driver communicates through.
public virtual ITransportConfiguration TransportConfiguration { get; }
Property Value
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
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
WebExtension
Gets the web extension module as described in the WebDriver BiDi protocol.
public WebExtensionModule WebExtension { get; }
Property Value
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
commandParametersCommandParametersThe object containing settings for the command, including parameters.
commandTimeoutTimeSpan?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.
cancellationTokenCancellationTokenA 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
TThe expected type of the result of the command.
Exceptions
- ArgumentOutOfRangeException
Thrown when
commandTimeoutis 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
cancellationTokenis canceled.- ObjectDisposedException
Thrown when attempting to call this method after the driver is disposed.
- ArgumentNullException
Thrown when
commandParametersis 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
commandParametersCommandParameters<T>The object containing settings for the command, including parameters.
commandTimeoutTimeSpan?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.
cancellationTokenCancellationTokenA 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
TThe expected type of the result of the command.
Exceptions
- ArgumentOutOfRangeException
Thrown when
commandTimeoutis 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
cancellationTokenis canceled.- ObjectDisposedException
Thrown when attempting to call this method after the driver is disposed.
- ArgumentNullException
Thrown when
commandParametersis 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
moduleNamestringThe name of the module to return.
Returns
- T
The protocol module object.
Type Parameters
TA 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
levelWebDriverBiDiLogLevelThe WebDriverBiDiLogLevel of the message the caller would raise.
Returns
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
messagestringThe log message to raise in the event.
logLevelWebDriverBiDiLogLevelThe 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
eventNamestringThe name of the event to raise.
eventInvokerFunc<EventInfo<T>, Task>The delegate taking a single parameter of type T used to invoke the event.
Type Parameters
TThe 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
moduleModuleThe 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
resolverIJsonTypeInfoResolverThe type info resolver to add.
cancellationTokenCancellationTokenA cancellation token that can be used to cancel the asynchronous operation.
Returns
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
cancellationTokenis 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
connectionStringstringThe connection string used to connect to the remote end. Usually the URL to the WebSocket used to communicate with the remote end.
cancellationTokenCancellationTokenA 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
connectionStringis 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 neitherwsnorwss. A different Connection type, such as PipeConnection, validates its own connection string and may not throw this.- OperationCanceledException
Thrown when
cancellationTokenis 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
cancellationTokenCancellationTokenA 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
cancellationTokenis canceled.