Class Transport
- Namespace
- WebDriverBiDi.Protocol
- Assembly
- WebDriverBiDi.dll
The transport object used for serializing and deserializing JSON data used in the WebDriver BiDi protocol. It uses a Connection object to communicate with the remote end, and does no further processing of the objects serialized or deserialized. Consumers of this class are expected to handle things like awaiting the response of a WebDriver BiDi command message.
public class Transport : IAsyncDisposable, ITransportConfiguration, ITransportDiagnostics
- Inheritance
-
Transport
- Implements
- Inherited Members
Remarks
Message Queue Architecture: This transport uses an unbounded Channel<T> for message processing. Messages received from the connection are queued and processed sequentially by a dedicated reader task.
Memory Considerations: The unbounded queue means there is no limit on the number of messages that can be buffered if they arrive faster than they can be processed. In typical usage, message processing is fast enough that queue depth remains minimal. However, in high-throughput scenarios (e.g., thousands of rapid events or very slow event handlers), memory consumption could grow significantly.
Performance Characteristics: The single-reader, single-writer queue design provides optimal throughput for the typical case where messages arrive sequentially and are processed quickly. Event handlers that perform slow operations (I/O, CPU-intensive work) should use RunHandlerAsynchronously to avoid blocking the message processing thread.
Monitoring Queue Behavior: Use IncomingQueueDepth to monitor the number of messages buffered in the queue. A persistently growing value indicates that event handlers are not keeping up with the incoming message rate. If you suspect message backlog issues, consider:
- Using RunHandlerAsynchronously for all event handlers that perform I/O or take more than a few milliseconds
- Reducing the frequency of subscribed events if not all are needed
- Implementing throttling or filtering logic in your event handlers
Thread Safety: This class is thread-safe. SendCommandAsync(CommandParameters, CancellationToken) may be called concurrently from multiple threads. Connection lifecycle operations (ConnectAsync(string, CancellationToken), DisconnectAsync(CancellationToken)) are serialized via an internal semaphore. Both DisconnectAsync(CancellationToken) and SendCommandAsync(CommandParameters, CancellationToken) check the connected state before taking the semaphore (and again after acquiring it). This prevents a deadlock when a disconnect is triggered while another caller already holds the lock, and lets a command sent from a synchronous event handler while DisconnectAsync(CancellationToken) is in progress fail immediately with WebDriverBiDiConnectionException rather than blocking on the semaphore for the duration of the shutdown wait. Event observers may be added or removed concurrently with message processing.
Constructors
Transport()
Initializes a new instance of the Transport class.
public Transport()
Transport(Connection)
Initializes a new instance of the Transport class with a given command timeout and connection.
public Transport(Connection connection)
Parameters
connectionConnectionThe Connection used to communicate with the protocol remote end.
Exceptions
- ArgumentNullException
Thrown when a null is passed for the connection.
- ArgumentException
Thrown when the provided Connection already has an observer for its OnDataReceived event.
Fields
LoggerComponentName
Gets the component name for this class to use in log messages.
public const string LoggerComponentName = "Transport"
Field Value
Properties
Connection
Gets the connection used to communicate with the browser.
protected Connection Connection { get; }
Property Value
ConnectionLockTimeout
Gets or sets the timeout to wait for exclusive access to this transport's connection while another operation holds it. The default is 60 seconds.
public TimeSpan ConnectionLockTimeout { get; set; }
Property Value
Remarks
ConnectAsync(string, CancellationToken), DisconnectAsync(CancellationToken), SendCommandAsync(CommandParameters, CancellationToken) and RegisterTypeInfoResolverAsync(IJsonTypeInfoResolver, CancellationToken) each take exclusive access for the duration of their work, so one of them waits while another is in progress. Bounding that wait keeps an operation issued from code this transport itself invoked while holding the access — a synchronous observer of OnLogMessage that sends a command, for example — from waiting on an operation that is itself waiting on the observer to return. Such an operation fails with WebDriverBiDiTimeoutException instead of never completing. An observer that needs to drive the transport should be registered with RunHandlerAsynchronously so that it does not hold up the operation it was dispatched from.
The default is deliberately longer than the longest legitimate hold, so that lowering it is a deliberate choice rather than a trap. A disconnect that exhausts every wait it is allowed holds the access for the connection's close handshake and for its receive-loop wait (each bounded by ShutdownTimeout), and then for the message-queue drain (bounded by ShutdownTimeout), which is about 30 seconds at the default settings. A value shorter than the longest hold a session can legitimately take will fail operations that would otherwise have succeeded. Zero never waits, and InfiniteTimeSpan restores an unbounded wait.
Disposal takes the access too, so that an operation holding it -- a connect attempt, a disconnect, or the teardown after a connection loss -- is not torn down from under itself. That wait is bounded by ShutdownTimeout and by this timeout alike; whichever elapses first ends it, a warning is raised on OnLogMessage, and disposal proceeds.
Handling a lost connection waits for the access too, on the connection's receive loop. A wait abandoned there leaves the session standing rather than tearing it down without the access: the transport stays Connected, its pending commands end at their own timeouts, and a Warn message naming the cause is raised on OnLogMessage.
Exceptions
- ArgumentOutOfRangeException
Thrown when the value is negative (other than InfiniteTimeSpan) or exceeds the maximum timer duration supported by the runtime.
EventHandlerExceptionBehavior
Gets or sets a value indicating how this Transport should behave when an
observer of an observable event throws, or the task it returns faults.
Defaults to Ignore, in which case the error is neither
collected nor thrown from a later call; it is still raised on OnEventHandlerErrorOccurred
and as the EventHandlerError event of WebDriverBiDiEventSource.
public TransportErrorBehavior EventHandlerExceptionBehavior { get; set; }
Property Value
IncomingQueueDepth
Gets the number of messages currently buffered in the incoming message queue and waiting to be processed by the reader task.
public virtual int IncomingQueueDepth { get; }
Property Value
Remarks
This property surfaces the depth of the unbounded Channel<T> described in the class-level remarks. It is intended for diagnostics and observability: a persistently growing value indicates that event handlers are not keeping up with the incoming message rate, and should prompt investigation of handler duration or the use of RunHandlerAsynchronously.
The value reflects the queue for the current connection. Each call to ConnectAsync(string, CancellationToken) installs a fresh queue whose depth begins at zero, and every message is counted against the queue it was written to for as long as that queue is being drained. A reconnect that gives up waiting for the previous connection's reader therefore reports only the current connection's backlog, even while the previous reader is still draining what remains of its own queue. Reading this property before ConnectAsync(string, CancellationToken) has ever been called, or after DisconnectAsync(CancellationToken), returns the depth of the remaining (possibly drained) queue rather than throwing.
Thread Safety: This property is safe to read concurrently with message production and consumption. The returned value is a snapshot and may be stale by the time the caller observes it.
LastCommandId
Gets the ID of the last command to be added.
protected long LastCommandId { get; }
Property Value
Remarks
This method uses Interlocked.Read for downlevel compatibility
with legacy and 32-bit framework implementations.
LogLevel
Gets or sets the minimum WebDriverBiDiLogLevel at which log messages are raised. Defaults to Info.
public virtual WebDriverBiDiLogLevel LogLevel { get; set; }
Property Value
Remarks
By default this is the same setting as LogLevel on the connection this transport wraps, which holds it for the whole pipeline; setting it here sets it for the connection's messages as well as this transport's own. Raise it to Debug for per-command messages, or to Trace to also see the raw protocol traffic the connection logs.
A derived transport may override this to keep a level of its own rather than share the
connection's. Note what that decouples: IsLogLevelEnabled(WebDriverBiDiLogLevel) and this transport's
LogAsync read this property, and so does the driver through
TransportConfiguration, so all three
follow the override; the connection keeps filtering its own messages — the SEND and
RECV traffic among them — by LogLevel. An override whose
setter also assigns LogLevel keeps the whole pipeline together.
MaxTrackedCanceledCommands
Gets or sets the number of most recent command cancellations within which a canceled command is remembered, so that a response arriving for it later is recognized and discarded. The default is DefaultMaxTrackedCanceledCommands.
public uint MaxTrackedCanceledCommands { get; set; }
Property Value
Remarks
A command that times out, or is canceled, may still be answered by the remote end. A response for a command still remembered is discarded quietly; a response for one that has been forgotten, because this many further commands were canceled after it, is treated as an unknown message or an unexpected error, as UnknownMessageBehavior and UnexpectedErrorBehavior direct. Raise the value if a session cancels many commands whose responses may arrive long afterwards. A value of zero disables the tracking.
Canceled commands are remembered per session, so the value takes effect for the session started by the next ConnectAsync(string, CancellationToken), and does not change the session in progress.
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 by the loop that dispatches the session's messages, after every message received before the loss, once the transport has torn the session down: its state is Disconnected and commands in flight have failed. Like any observer run on that loop, an observer can stop the transport, but connecting it again waits for the loop to finish, at most ShutdownTimeout, so reconnect from outside the observer, or from one added with RunHandlerAsynchronously. It is not raised when the client stops the transport, nor for a connection lost while it is being established, which fails the start 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
OnEventReceived
Gets an observable event that notifies when an event is received from the protocol.
public ObservableEvent<EventReceivedEventArgs> OnEventReceived { get; }
Property Value
OnLogMessage
Gets an observable event that notifies when a log message is written.
public ObservableEvent<LogMessageEventArgs> OnLogMessage { get; }
Property Value
OnUnexpectedErrorReceived
Gets an observable event that notifies when an error is received from the protocol that is not the result of a command execution.
public ObservableEvent<ErrorReceivedEventArgs> OnUnexpectedErrorReceived { get; }
Property Value
OnUnknownMessageReceived
Gets an observable event that notifies when an unknown message is received from the protocol.
public ObservableEvent<UnknownMessageReceivedEventArgs> OnUnknownMessageReceived { get; }
Property Value
PendingCommandCount
Gets the number of commands that have been sent to the remote end and are awaiting a response.
public virtual int PendingCommandCount { get; }
Property Value
Remarks
This property is intended for diagnostics and observability alongside IncomingQueueDepth. A persistently high value suggests that the remote end is not responding promptly, or that a burst of commands is in flight without corresponding responses yet.
Reading this property before ConnectAsync(string, CancellationToken) has ever been called, or after DisconnectAsync(CancellationToken), returns the count of the pending-command collection in its current state rather than throwing. The collection is cleared during DisconnectAsync(CancellationToken), so reads after a disconnect typically return zero.
Thread Safety: This property is safe to read concurrently with command send and response processing. The returned value is a snapshot and may be stale by the time the caller observes it.
PendingCommands
Gets the collection of pending commands of the current session: commands that have been sent and have not yet received a response. This collection is thread-safe.
protected PendingCommandCollection PendingCommands { get; }
Property Value
Remarks
Each session has its own collection, created by ConnectAsync(string, CancellationToken) with the capacity set by MaxTrackedCanceledCommands, so the collection returned here changes when the transport reconnects.
ProtocolErrorBehavior
Gets or sets a value indicating how this Transport should behave when a
protocol error is encountered: a message recognized as an error response or as a registered event
whose payload cannot be deserialized, or an unexpected failure while processing an incoming message.
An error response whose ID matches a pending command is not a protocol error; it fails that command.
A message that cannot be parsed as JSON at all is an unknown message (see UnknownMessageBehavior).
Defaults to Ignore, in which case the error is neither
collected nor thrown from a later call; it is still written to OnLogMessage at
Error and, for a payload that cannot be deserialized, raised as the
ProtocolError event of WebDriverBiDiEventSource as well. A fault of the
message-processing loop itself raises that EventSource event and is not logged. No observable event is
raised for any of them.
public TransportErrorBehavior ProtocolErrorBehavior { get; set; }
Property Value
ShutdownTimeout
Gets or sets the timeout to wait for message processing to complete during shutdown. If message processing does not complete within this timeout, the shutdown stops waiting and proceeds, and any pending commands are canceled. The default is 10 seconds.
public TimeSpan ShutdownTimeout { get; set; }
Property Value
Remarks
This timeout applies to waiting for the incoming message queue to empty, to waiting for the messages in the queue to be processed, and, during disposal, to waiting for an in-flight connect attempt to complete before the transport's resources are released.
Abandoning the wait does not stop the reader. Messages already delivered to the queue go on being processed in the background, and their handlers go on running; what this timeout bounds is how long the shutdown waits for them, not whether they run. A subsequent ConnectAsync(string, CancellationToken) waits for that processing to finish, bounded by this same timeout, before opening a new connection.
Exceptions
- ArgumentOutOfRangeException
Thrown when the value is negative (other than InfiniteTimeSpan) or exceeds the maximum timer duration supported by the runtime.
State
Gets a value indicating the lifecycle state of this transport with respect to its connection to a remote end. The returned value is a snapshot and may be stale by the time the caller observes it.
public TransportState State { get; }
Property Value
Remarks
Every state transition is performed while holding the connection lock (or, in the case of a connection-loss transition, while racing that lock for ownership), so the setter is an unconditional atomic publish; no compare-and-swap is required.
TimeProvider
Gets or sets the TimeProvider whose clock measures this transport's ShutdownTimeout waits. Defaults to System. A derived type may substitute another, for example to drive the waits with virtual time in a test, in the same way that ObservableEvent<T> exposes its provider to derived types. The Connection measures its own timeouts with its own provider.
protected TimeProvider TimeProvider { get; set; }
Property Value
- TimeProvider
UnexpectedErrorBehavior
Gets or sets a value indicating how this Transport should behave when an unexpected error is encountered, meaning an error response received with no corresponding command. Defaults to Ignore, in which case the error is neither collected nor thrown from a later call; it is still raised on OnUnexpectedErrorReceived. An error response for a command that has timed out or been canceled is not an unexpected error; it is recognized, logged, and discarded (see CancelCommand(Command, CommandCancellationReason)).
public TransportErrorBehavior UnexpectedErrorBehavior { get; set; }
Property Value
UnhandledErrors
Gets the collection of unhandled errors captured by this transport. This collection is thread-safe. Use this collection to inspect unhandled errors that have been captured, and to clear captured errors if desired.
protected UnhandledErrorCollection UnhandledErrors { get; }
Property Value
UnknownMessageBehavior
Gets or sets a value indicating how this Transport should behave when an
unknown message is encountered: a message that cannot be parsed as JSON, or one that is not a
command response, an error response, or an event registered with this transport, such as a
response for a command ID that was never issued or an event whose name is not registered.
Defaults to Ignore, in which case the error is neither
collected nor thrown from a later call; it is still raised on OnUnknownMessageReceived
and as the UnknownMessageReceived event of WebDriverBiDiEventSource, and a message
that cannot be parsed is also written to OnLogMessage at Error.
A response for a command that has timed out or been canceled is
not an unknown message; it is recognized, logged, and discarded (see
CancelCommand(Command, CommandCancellationReason)).
public TransportErrorBehavior UnknownMessageBehavior { get; set; }
Property Value
Methods
AcquireConnectionLockAsync(CancellationToken)
Asynchronously acquires the connection lock to ensure thread-safe operations for connection-related actions.
protected virtual Task AcquireConnectionLockAsync(CancellationToken cancellationToken = default)
Parameters
cancellationTokenCancellationTokenA cancellation token that can be used to cancel the asynchronous operation.
Returns
- Task
A task that represents the asynchronous acquire operation.
Remarks
The uncontended case is the overwhelmingly common one, and it is taken without allocating: the timeout machinery is built only once the lock is found to be held. The bound is measured on this transport's TimeProvider, so a transport running on virtual time waits on that same clock.
Bounding the wait is what keeps a re-entrant call from hanging forever. This transport dispatches observers while holding the lock — the connection raises its own traffic message from inside SendDataAsync(ReadOnlyMemory<byte>, CancellationToken), and both the connection and this transport log around connect and disconnect — so a synchronous observer that calls back into the transport arrives here for a lock its own caller holds. It now fails with a WebDriverBiDiTimeoutException naming the cause, and the operation it interrupted proceeds, rather than the two waiting on each other indefinitely.
Exceptions
- WebDriverBiDiTimeoutException
Thrown when the lock is not acquired within ConnectionLockTimeout.
- OperationCanceledException
Thrown when
cancellationTokenis canceled.
AddEventMessageType(string, Type)
Adds an event message type to the map of known event message types. To intercept or rewrite registrations, override RegisterEventMessage<T>(string), which the driver calls.
protected void AddEventMessageType(string eventName, Type eventMessageType)
Parameters
eventNamestringThe name of the event.
eventMessageTypeTypeThe type of data to be returned in the event.
Remarks
The type is deserialized through the serializer's metadata for it, because the envelope
converter needs the payload type as a compile-time argument and building it for a runtime
Type would need reflection, which native AOT cannot keep. Envelopes registered
this way are therefore read more leniently than those registered through
RegisterEventMessage<T>(string): a missing method or a null params is
accepted here, and surfaces later as a protocol error rather than as a deserialization
failure. Register through RegisterEventMessage<T>(string) wherever the payload type is
known at compile time.
CancelCommand(Command, CommandCancellationReason)
Cancels a pending command and removes it from the pending command collection. If the command has already completed or been removed, this method is a safe no-op.
public virtual bool CancelCommand(Command command, CommandCancellationReason reason = CommandCancellationReason.Canceled)
Parameters
commandCommandThe command to cancel.
reasonCommandCancellationReasonThe reason the command is being canceled.
Returns
- bool
true if the cancellation took effect; false if the command had already completed with a result or fault, in which case that outcome stands.
Remarks
The remote end does not know that the local end has stopped waiting, so it may still send a response for the canceled command. The command is remembered (see CancelPendingCommand(Command, CommandCancellationReason)) so that such a response is recognized and discarded rather than being reported as an unknown message or an unexpected error.
CaptureUnhandledError(UnhandledErrorKind, Exception, string)
Captures an unhandled error in the protocol.
protected virtual void CaptureUnhandledError(UnhandledErrorKind errorType, Exception ex, string terminalReason)
Parameters
errorTypeUnhandledErrorKindThe UnhandledErrorKind describing the type of error.
exExceptionThe exception thrown for the error.
terminalReasonstringThe reason for terminating the session, if the error is a terminal error.
Remarks
This method is protected virtual to allow test doubles to
precisely determine when an unhandled error has been captured and propagated
to the unhandled errors collection.
ConnectAsync(string, CancellationToken)
Asynchronously connects to the remote end web socket.
public virtual Task ConnectAsync(string connectionString, CancellationToken cancellationToken = default)
Parameters
connectionStringstringThe URI used to connect to the web socket.
cancellationTokenCancellationTokenA cancellation token used to propagate notification that the operation should be canceled.
Returns
- Task
The task object representing the asynchronous operation.
Remarks
Connecting starts a new session and clears the errors the previous session accumulated under Collect. Those errors are thrown only by DisconnectAsync(CancellationToken). After a remote disconnect the transport is already in the Disconnected state, so this method proceeds; to observe the errors collected up to the disconnect, call DisconnectAsync(CancellationToken) (which returns promptly and throws them) before reconnecting. Reconnecting directly discards them.
A Connection that is already open is adopted rather than opened again, so a caller
who opened the connection themselves before handing it to this transport may start a session over
it. Because nothing is opened in that case, connectionString cannot select a
different remote end, and one that names a different remote end is rejected rather than silently
ignored: pass the value the connection was opened with, or stop the connection first and let this
method open it. The two values are compared exactly, so a string that names the same remote end
in a different form (a different case, or a trailing slash) is treated as a different one. A
connection that is not open is unaffected by any of this, including one being reopened to a
different remote end after DisconnectAsync(CancellationToken).
Exceptions
- WebDriverBiDiConnectionException
Thrown when the transport is already connected to a remote end, when the Connection refuses to open, or when the connection is lost while the session is being established. The last case carries the loss the connection reported as its inner exception; the transport is left disconnected, so a further attempt may be made.
- WebDriverBiDiTimeoutException
Propagated from StartAsync(string, CancellationToken) when the connection is not established within its StartupTimeout.
- ArgumentException
Propagated from StartAsync(string, CancellationToken) when
connectionStringis not acceptable to the connection, or when the Connection is already connected with a ConnectionString different thanconnectionString. WebSocketConnection throws this when the value is not a valid absolute URI, or when its scheme is neitherwsnorwss.- OperationCanceledException
Thrown when
cancellationTokenis canceled.- ObjectDisposedException
Thrown when the transport is disposed, including when disposal begins while this attempt is waiting for the connection lock or is connecting; the attempt then fails rather than connecting a transport that is being disposed.
CreateCommand(CommandParameters)
Creates a Command object from the specified command parameters.
protected virtual Command CreateCommand(CommandParameters commandData)
Parameters
commandDataCommandParametersThe CommandParameters object containing the command data.
Returns
Remarks
This method allows a developer to override the creation of a command. This is useful for cases where additional properties need to be sent in the command envelope as opposed to the command parameters object.
CreateIncomingMessage(IMemoryOwner<byte>, int)
Creates an IncomingMessage object for the data received by this Transport.
protected virtual IncomingMessage CreateIncomingMessage(IMemoryOwner<byte> owner, int length)
Parameters
ownerIMemoryOwner<byte>The IMemoryOwner<T> whose buffer contains the incoming message data. Ownership transfers to the returned IncomingMessage, which will dispose it on disposal.
lengthintThe length, in bytes, of the incoming message within the owner's buffer.
Returns
- IncomingMessage
The IncomingMessage object for the data received.
DisconnectAsync(bool, CancellationToken)
Asynchronously disconnects from the remote end web socket.
protected virtual Task DisconnectAsync(bool throwCollectedExceptions, CancellationToken cancellationToken = default)
Parameters
throwCollectedExceptionsboolA value indicating whether to throw the collected exceptions.
cancellationTokenCancellationTokenA cancellation token used to propagate notification that the operation should be canceled.
Returns
- Task
The task object representing the asynchronous operation.
DisconnectAsync(CancellationToken)
Asynchronously disconnects from the remote end web socket.
public virtual Task DisconnectAsync(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. They are thrown at most once per session, by whichever disconnect claims them.
- WebDriverBiDiTimeoutException
Thrown when exclusive access to the connection is not obtained within ConnectionLockTimeout.
- OperationCanceledException
Thrown when
cancellationTokenis canceled.
DisposeAsync()
Asynchronously releases the resources used by this Transport.
public ValueTask DisposeAsync()
Returns
- ValueTask
A task that represents the asynchronous dispose operation.
Remarks
Disposing a transport that is already disposed does nothing, as IAsyncDisposable requires. The teardown cannot simply be repeated: it releases resources that are then gone, and a second run would again wait, up to ShutdownTimeout, for an operation still holding the connection lock, which is what remains when the first run's wait for that operation timed out.
DisposeAsyncCore()
Asynchronously releases the resources used by this Transport. 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.
Remarks
DisposeAsync() calls this method once, on the first disposal only, and records the disposal before calling it, so an override neither repeats that guard nor needs one of its own. Because the transport is marked disposed before the teardown rather than after it, an operation that rejects a disposed transport -- ConnectAsync(string, CancellationToken), SendCommandAsync(CommandParameters, CancellationToken) and RegisterTypeInfoResolverAsync(IJsonTypeInfoResolver, CancellationToken) -- fails from the moment disposal begins rather than only once it has finished.
The teardown first waits, up to ShutdownTimeout, for any operation holding the connection lock to finish: a connect attempt, a disconnect, or the teardown after a connection loss. A connect attempt still in progress then fails with ObjectDisposedException rather than completing. If the wait times out, the teardown proceeds without it, and the operation still holding the lock finishes against the disposed transport.
GetNextCommandId()
Increments the command ID for the command to be sent.
protected long GetNextCommandId()
Returns
- long
The command ID for the command to be sent.
Remarks
Command IDs are unique for the lifetime of the transport; they are not reset when the transport reconnects. A response still in flight from a previous session, such as one delivered late over a connection that survives the reconnect, therefore cannot be mistaken for the response to a command of the current session.
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
The transport uses this for its per-command Debug messages, each of which composes a string naming the command; a custom transport should use it for the same purpose. 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.
ProcessMessageAsync(IncomingMessage, PendingCommandCollection)
Processes a single incoming message read from the connection.
protected virtual Task ProcessMessageAsync(IncomingMessage packet, PendingCommandCollection pendingCommands)
Parameters
packetIncomingMessageThe incoming message to process.
pendingCommandsPendingCommandCollectionThe pending commands of the session on whose connection the message was received, against which a response in the message is resolved. After a reconnect, this is not the collection in PendingCommands for a message the previous session's reader is still processing.
Returns
Remarks
This method is protected virtual to allow test doubles to observe or delay the
processing of individual messages (for example to create a backlog of pending messages while the
transport disconnects).
ReadIncomingMessagesAsync()
Reads and processes messages from the incoming message queue until the queue is closed. This method is the body of the task started by ConnectAsync(string, CancellationToken).
protected virtual Task ReadIncomingMessagesAsync()
Returns
- Task
A task representing the asynchronous message-processing loop.
Remarks
This method is protected virtual to allow test doubles to
substitute the message-processing loop — for example, to simulate an
unrecoverable fault on the outer await so that the fault continuation attached
in ConnectAsync(string, CancellationToken) can be exercised.
RegisterEventMessage<T>(string)
Registers an event message to be recognized when received from the connection.
public virtual void RegisterEventMessage<T>(string eventName)
Parameters
eventNamestringThe name of the event.
Type Parameters
TThe type of data to be returned in the event.
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 transport is not connected: before the first connection, or after a disconnect. 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
resolveris null.- ObjectDisposedException
Thrown when the transport has been disposed.
- InvalidOperationException
Thrown if the transport is already connected to a remote end.
- WebDriverBiDiTimeoutException
Thrown when exclusive access to the connection is not obtained within ConnectionLockTimeout.
- OperationCanceledException
Thrown when
cancellationTokenis canceled.
ReleaseConnectionLock()
Releases the connection lock to allow other threads to perform connection-related actions.
protected virtual void ReleaseConnectionLock()
SendCommandAsync(CommandParameters, CancellationToken)
Asynchronously sends a command to the remote end.
public virtual Task<Command> SendCommandAsync(CommandParameters commandData, CancellationToken cancellationToken = default)
Parameters
commandDataCommandParametersThe command settings object containing all data required to execute the command.
cancellationTokenCancellationTokenA cancellation token used to propagate notification that the operation should be canceled.
Returns
Exceptions
- WebDriverBiDiException
Thrown if the command ID is already in use.
- WebDriverBiDiSerializationException
Thrown if the command parameters cannot be serialized to JSON: when an extension-data entry on the command or on any object inside its parameters uses a property name that object already serializes; when an object-typed member holds a value JSON cannot express, such as a non-finite double; or when a value's type has no serialization metadata. The failure that caused it is the InnerException.
- WebDriverBiDiConnectionException
Thrown when the transport is not connected to a remote end.
- WebDriverBiDiTimeoutException
Thrown when exclusive access to the connection is not obtained within ConnectionLockTimeout.
- ArgumentNullException
Thrown when the command parameters are null.
- OperationCanceledException
Thrown when
cancellationTokenis canceled.
SerializeCommand(Command)
Serializes a command for transmission across the WebSocket connection.
protected virtual byte[] SerializeCommand(Command command)
Parameters
commandCommandThe command to serialize.
Returns
- byte[]
The UTF-8 encoded JSON bytes representing the command.