diff --git a/dotnet/src/webdriver/DevTools/DevToolsCommandData.cs b/dotnet/src/webdriver/DevTools/DevToolsCommandData.cs index 95e665fb634a3..cbc30ed42cc87 100644 --- a/dotnet/src/webdriver/DevTools/DevToolsCommandData.cs +++ b/dotnet/src/webdriver/DevTools/DevToolsCommandData.cs @@ -35,7 +35,7 @@ public class DevToolsCommandData /// /// Initializes a new instance of the DevToolsCommandData class. /// - /// The ID of the commmand execution. + /// The ID of the command execution. /// The method name of the DevTools command. /// The parameters of the DevTools command. /// If is . @@ -47,7 +47,7 @@ public DevToolsCommandData(long commandId, string commandName, JsonNode commandP /// /// Initializes a new instance of the DevToolsCommandData class. /// - /// The ID of the commmand execution. + /// The ID of the command execution. /// The session ID of the current command execution. /// The method name of the DevTools command. /// The parameters of the DevTools command. diff --git a/dotnet/src/webdriver/DevTools/DevToolsSession.cs b/dotnet/src/webdriver/DevTools/DevToolsSession.cs index a11f4757776a3..aebbc46d9467f 100644 --- a/dotnet/src/webdriver/DevTools/DevToolsSession.cs +++ b/dotnet/src/webdriver/DevTools/DevToolsSession.cs @@ -27,11 +27,13 @@ using System.Threading; using System.Threading.Tasks; +#nullable enable + namespace OpenQA.Selenium.DevTools { /// /// Represents a WebSocket connection to a running DevTools instance that can be used to send - /// commands and recieve events. + /// commands and receive events. /// public class DevToolsSession : IDevToolsSession { @@ -42,20 +44,17 @@ public class DevToolsSession : IDevToolsSession public const int AutoDetectDevToolsProtocolVersion = 0; private readonly string debuggerEndpoint; - private string websocketAddress; private readonly TimeSpan openConnectionWaitTimeSpan = TimeSpan.FromSeconds(30); private readonly TimeSpan closeConnectionWaitTimeSpan = TimeSpan.FromSeconds(2); private bool isDisposed = false; - private string attachedTargetId; + private string? attachedTargetId; - private WebSocketConnection connection; + private WebSocketConnection? connection; private ConcurrentDictionary pendingCommands = new ConcurrentDictionary(); private readonly BlockingCollection messageQueue = new BlockingCollection(); private readonly Task messageQueueMonitorTask; private long currentCommandId = 0; - - private DevToolsDomains domains; private readonly DevToolsOptions options; private readonly static ILogger logger = Internal.Logging.Log.GetLogger(); @@ -72,7 +71,7 @@ public class DevToolsSession : IDevToolsSession /// /// /// - /// + /// If is , or is or . public DevToolsSession(string endpointAddress, DevToolsOptions options) { if (string.IsNullOrWhiteSpace(endpointAddress)) @@ -85,7 +84,7 @@ public DevToolsSession(string endpointAddress, DevToolsOptions options) this.debuggerEndpoint = endpointAddress; if (endpointAddress.StartsWith("ws", StringComparison.InvariantCultureIgnoreCase)) { - this.websocketAddress = endpointAddress; + this.EndpointAddress = endpointAddress; } this.messageQueueMonitorTask = Task.Run(() => this.MonitorMessageQueue()); } @@ -93,12 +92,12 @@ public DevToolsSession(string endpointAddress, DevToolsOptions options) /// /// Event raised when the DevToolsSession logs informational messages. /// - public event EventHandler LogMessage; + public event EventHandler? LogMessage; /// /// Event raised an event notification is received from the DevTools session. /// - public event EventHandler DevToolsEventReceived; + public event EventHandler? DevToolsEventReceived; /// /// Gets or sets the time to wait for a command to complete. Default is 30 seconds. @@ -108,17 +107,17 @@ public DevToolsSession(string endpointAddress, DevToolsOptions options) /// /// Gets or sets the active session ID of the connection. /// - public string ActiveSessionId { get; private set; } + public string? ActiveSessionId { get; private set; } /// /// Gets the endpoint address of the session. /// - public string EndpointAddress => this.websocketAddress; + public string? EndpointAddress { get; private set; } /// /// Gets the version-independent domain implementation for this Developer Tools connection /// - public DevToolsDomains Domains => this.domains; + public DevToolsDomains Domains { get; private set; } = null!; // TODO handle nullability for this /// /// Gets the version-specific implementation of domains for this DevTools session. @@ -128,11 +127,10 @@ public DevToolsSession(string endpointAddress, DevToolsOptions options) /// The version-specific DevTools Protocol domain implementation. public T GetVersionSpecificDomains() where T : DevToolsSessionDomains { - T versionSpecificDomains = this.domains.VersionSpecificDomains as T; - if (versionSpecificDomains == null) + if (this.Domains.VersionSpecificDomains is not T versionSpecificDomains) { string errorTemplate = "The type is invalid for conversion. You requested domains of type '{0}', but the version-specific domains for this session are '{1}'"; - string exceptionMessage = string.Format(CultureInfo.InvariantCulture, errorTemplate, typeof(T).ToString(), this.domains.GetType().ToString()); + string exceptionMessage = string.Format(CultureInfo.InvariantCulture, errorTemplate, typeof(T).ToString(), this.Domains.GetType().ToString()); throw new InvalidOperationException(exceptionMessage); } @@ -148,7 +146,7 @@ public T GetVersionSpecificDomains() where T : DevToolsSessionDomains /// The execution timeout of the command in milliseconds. /// to throw an exception if a response is not received; otherwise, . /// The command response object implementing the interface. - public async Task> SendCommand(TCommand command, CancellationToken cancellationToken = default(CancellationToken), int? millisecondsTimeout = null, bool throwExceptionIfResponseNotReceived = true) + public async Task?> SendCommand(TCommand command, CancellationToken cancellationToken = default, int? millisecondsTimeout = null, bool throwExceptionIfResponseNotReceived = true) where TCommand : ICommand { if (command == null) @@ -156,14 +154,15 @@ public T GetVersionSpecificDomains() where T : DevToolsSessionDomains throw new ArgumentNullException(nameof(command)); } - var result = await SendCommand(command.CommandName, JsonSerializer.SerializeToNode(command), cancellationToken, millisecondsTimeout, throwExceptionIfResponseNotReceived).ConfigureAwait(false); + JsonNode commandParameters = JsonSerializer.SerializeToNode(command) ?? throw new InvalidOperationException("Command serialized to \"null\"."); + var result = await SendCommand(command.CommandName, commandParameters, cancellationToken, millisecondsTimeout, throwExceptionIfResponseNotReceived).ConfigureAwait(false); if (result == null) { return null; } - if (!this.domains.VersionSpecificDomains.ResponseTypeMap.TryGetCommandResponseType(out Type commandResponseType)) + if (!this.Domains.VersionSpecificDomains.ResponseTypeMap.TryGetCommandResponseType(out Type? commandResponseType)) { throw new InvalidOperationException($"Type {command.GetType()} does not correspond to a known command response type."); } @@ -181,7 +180,7 @@ public T GetVersionSpecificDomains() where T : DevToolsSessionDomains /// The execution timeout of the command in milliseconds. /// to throw an exception if a response is not received; otherwise, . /// The command response object implementing the interface. - public async Task> SendCommand(TCommand command, string sessionId, CancellationToken cancellationToken = default(CancellationToken), int? millisecondsTimeout = null, bool throwExceptionIfResponseNotReceived = true) + public async Task?> SendCommand(TCommand command, string sessionId, CancellationToken cancellationToken = default, int? millisecondsTimeout = null, bool throwExceptionIfResponseNotReceived = true) where TCommand : ICommand { if (command == null) @@ -189,14 +188,15 @@ public T GetVersionSpecificDomains() where T : DevToolsSessionDomains throw new ArgumentNullException(nameof(command)); } - var result = await SendCommand(command.CommandName, sessionId, JsonSerializer.SerializeToNode(command), cancellationToken, millisecondsTimeout, throwExceptionIfResponseNotReceived).ConfigureAwait(false); + JsonNode commandParameters = JsonSerializer.SerializeToNode(command) ?? throw new InvalidOperationException("Command serialized to \"null\"."); + var result = await SendCommand(command.CommandName, sessionId, commandParameters, cancellationToken, millisecondsTimeout, throwExceptionIfResponseNotReceived).ConfigureAwait(false); if (result == null) { return null; } - if (!this.domains.VersionSpecificDomains.ResponseTypeMap.TryGetCommandResponseType(command, out Type commandResponseType)) + if (!this.Domains.VersionSpecificDomains.ResponseTypeMap.TryGetCommandResponseType(command, out Type? commandResponseType)) { throw new InvalidOperationException($"Type {typeof(TCommand)} does not correspond to a known command response type."); } @@ -214,7 +214,7 @@ public T GetVersionSpecificDomains() where T : DevToolsSessionDomains /// The execution timeout of the command in milliseconds. /// to throw an exception if a response is not received; otherwise, . /// The command response object implementing the interface. - public async Task SendCommand(TCommand command, CancellationToken cancellationToken = default(CancellationToken), int? millisecondsTimeout = null, bool throwExceptionIfResponseNotReceived = true) + public async Task SendCommand(TCommand command, CancellationToken cancellationToken = default, int? millisecondsTimeout = null, bool throwExceptionIfResponseNotReceived = true) where TCommand : ICommand where TCommandResponse : ICommandResponse { @@ -223,11 +223,12 @@ public T GetVersionSpecificDomains() where T : DevToolsSessionDomains throw new ArgumentNullException(nameof(command)); } - var result = await SendCommand(command.CommandName, JsonSerializer.SerializeToNode(command), cancellationToken, millisecondsTimeout, throwExceptionIfResponseNotReceived).ConfigureAwait(false); + JsonNode commandParameters = JsonSerializer.SerializeToNode(command) ?? throw new InvalidOperationException("Command serialized to \"null\"."); + var result = await SendCommand(command.CommandName, commandParameters, cancellationToken, millisecondsTimeout, throwExceptionIfResponseNotReceived).ConfigureAwait(false); if (result == null) { - return default(TCommandResponse); + return default; } return result.Value.Deserialize(); @@ -242,8 +243,7 @@ public T GetVersionSpecificDomains() where T : DevToolsSessionDomains /// The execution timeout of the command in milliseconds. /// to throw an exception if a response is not received; otherwise, . /// The command response object implementing the interface. - //[DebuggerStepThrough] - public async Task SendCommand(string commandName, JsonNode commandParameters, CancellationToken cancellationToken = default(CancellationToken), int? millisecondsTimeout = null, bool throwExceptionIfResponseNotReceived = true) + public async Task SendCommand(string commandName, JsonNode commandParameters, CancellationToken cancellationToken = default, int? millisecondsTimeout = null, bool throwExceptionIfResponseNotReceived = true) { if (this.attachedTargetId == null) { @@ -264,13 +264,9 @@ public T GetVersionSpecificDomains() where T : DevToolsSessionDomains /// The execution timeout of the command in milliseconds. /// to throw an exception if a response is not received; otherwise, . /// The command response object implementing the interface. - //[DebuggerStepThrough] - public async Task SendCommand(string commandName, string sessionId, JsonNode commandParameters, CancellationToken cancellationToken = default(CancellationToken), int? millisecondsTimeout = null, bool throwExceptionIfResponseNotReceived = true) + public async Task SendCommand(string commandName, string? sessionId, JsonNode commandParameters, CancellationToken cancellationToken = default, int? millisecondsTimeout = null, bool throwExceptionIfResponseNotReceived = true) { - if (millisecondsTimeout.HasValue == false) - { - millisecondsTimeout = Convert.ToInt32(CommandTimeout.TotalMilliseconds); - } + millisecondsTimeout ??= Convert.ToInt32(CommandTimeout.TotalMilliseconds); var message = new DevToolsCommandData(Interlocked.Increment(ref this.currentCommandId), sessionId, commandName, commandParameters); @@ -294,7 +290,7 @@ public T GetVersionSpecificDomains() where T : DevToolsSessionDomains throw new InvalidOperationException($"A command response was not received: {commandName}, timeout: {millisecondsTimeout.Value}ms"); } - if (this.pendingCommands.TryRemove(message.CommandId, out DevToolsCommandData modified)) + if (this.pendingCommands.TryRemove(message.CommandId, out DevToolsCommandData? modified)) { if (modified.IsError) { @@ -307,7 +303,7 @@ public T GetVersionSpecificDomains() where T : DevToolsSessionDomains exceptionMessage = $"{exceptionMessage} - {errorData}"; } - LogTrace("Recieved Error Response {0}: {1} {2}", modified.CommandId, message, errorData); + LogTrace("Received Error Response {0}: {1} {2}", modified.CommandId, message, errorData); throw new CommandResponseException(exceptionMessage) { Code = modified.Result.TryGetProperty("code", out var code) ? code.GetInt64() : -1 @@ -331,6 +327,7 @@ public T GetVersionSpecificDomains() where T : DevToolsSessionDomains public void Dispose() { this.Dispose(true); + GC.SuppressFinalize(this); } /// @@ -339,16 +336,17 @@ public void Dispose() /// A task that represents the asynchronous operation. internal async Task StartSession() { - var requestedProtocolVersion = options.ProtocolVersion.HasValue ? options.ProtocolVersion.Value : AutoDetectDevToolsProtocolVersion; + int requestedProtocolVersion = options.ProtocolVersion ?? AutoDetectDevToolsProtocolVersion; int protocolVersion = await InitializeProtocol(requestedProtocolVersion).ConfigureAwait(false); - this.domains = DevToolsDomains.InitializeDomains(protocolVersion, this); + this.Domains = DevToolsDomains.InitializeDomains(protocolVersion, this); + await this.InitializeSocketConnection().ConfigureAwait(false); await this.InitializeSession().ConfigureAwait(false); try { // Wrap this in a try-catch, because it's not the end of the // world if clearing the log doesn't work. - await this.domains.Log.Clear().ConfigureAwait(false); + await this.Domains.Log.Clear().ConfigureAwait(false); LogTrace("Log cleared.", this.attachedTargetId); } catch (WebDriverException) @@ -360,14 +358,14 @@ internal async Task StartSession() /// Asynchronously stops the session. /// /// to manually detach the session - /// from its attached target; otherswise . + /// from its attached target; otherwise . /// A task that represents the asynchronous operation. internal async Task StopSession(bool manualDetach) { if (this.attachedTargetId != null) { this.Domains.Target.TargetDetached -= this.OnTargetDetached; - string sessionId = this.ActiveSessionId; + string? sessionId = this.ActiveSessionId; this.ActiveSessionId = null; if (manualDetach) { @@ -400,23 +398,22 @@ protected void Dispose(bool disposing) private async Task InitializeProtocol(int requestedProtocolVersion) { int protocolVersion = requestedProtocolVersion; - if (this.websocketAddress == null) + if (this.EndpointAddress == null) { string debuggerUrl = string.Format(CultureInfo.InvariantCulture, "http://{0}", this.debuggerEndpoint); - string rawVersionInfo = string.Empty; + string rawVersionInfo; using (HttpClient client = new HttpClient()) { client.BaseAddress = new Uri(debuggerUrl); rawVersionInfo = await client.GetStringAsync("/json/version").ConfigureAwait(false); } - var versionInfo = JsonSerializer.Deserialize(rawVersionInfo); - this.websocketAddress = versionInfo.WebSocketDebuggerUrl; + var versionInfo = JsonSerializer.Deserialize(rawVersionInfo) ?? throw new JsonException("/json/version endpoint returned null response"); + this.EndpointAddress = versionInfo.WebSocketDebuggerUrl; if (requestedProtocolVersion == AutoDetectDevToolsProtocolVersion) { - bool versionParsed = int.TryParse(versionInfo.BrowserMajorVersion, out protocolVersion); - if (!versionParsed) + if (!int.TryParse(versionInfo.BrowserMajorVersion, out protocolVersion)) { throw new WebDriverException(string.Format(CultureInfo.InvariantCulture, "Unable to parse version number received from browser. Reported browser version string is '{0}'", versionInfo.Browser)); } @@ -443,7 +440,7 @@ private async Task InitializeSession() // that when getting the available targets, we won't // recursively try to call InitializeSession. this.attachedTargetId = ""; - var targets = await this.domains.Target.GetTargets().ConfigureAwait(false); + var targets = await this.Domains.Target.GetTargets().ConfigureAwait(false); foreach (var target in targets) { if (target.Type == "page") @@ -458,30 +455,30 @@ private async Task InitializeSession() if (this.attachedTargetId == "") { this.attachedTargetId = null; - throw new WebDriverException("Unable to find target to attach to, no taargets of type 'page' available"); + throw new WebDriverException("Unable to find target to attach to, no targets of type 'page' available"); } - string sessionId = await this.domains.Target.AttachToTarget(this.attachedTargetId).ConfigureAwait(false); + string sessionId = await this.Domains.Target.AttachToTarget(this.attachedTargetId).ConfigureAwait(false); LogTrace("Target ID {0} attached. Active session ID: {1}", this.attachedTargetId, sessionId); this.ActiveSessionId = sessionId; - await this.domains.Target.SetAutoAttach().ConfigureAwait(false); + await this.Domains.Target.SetAutoAttach().ConfigureAwait(false); LogTrace("AutoAttach is set.", this.attachedTargetId); - // The Target domain needs to send Sessionless commands! Else the waitForDebugger setting in setAutoAttach wont work! + // The Target domain needs to send Session-less commands! Else the waitForDebugger setting in setAutoAttach wont work! if (options.WaitForDebuggerOnStart) { - var setAutoAttachCommand = domains.Target.CreateSetAutoAttachCommand(true); - var setDiscoverTargetsCommand = domains.Target.CreateDiscoverTargetsCommand(); + var setAutoAttachCommand = Domains.Target.CreateSetAutoAttachCommand(true); + var setDiscoverTargetsCommand = Domains.Target.CreateDiscoverTargetsCommand(); - await SendCommand(setAutoAttachCommand, string.Empty, default(CancellationToken), null, true).ConfigureAwait(false); - await SendCommand(setDiscoverTargetsCommand, string.Empty, default(CancellationToken), null, true).ConfigureAwait(false); + await SendCommand(setAutoAttachCommand, string.Empty, default, null, true).ConfigureAwait(false); + await SendCommand(setDiscoverTargetsCommand, string.Empty, default, null, true).ConfigureAwait(false); } - this.domains.Target.TargetDetached += this.OnTargetDetached; + this.Domains.Target.TargetDetached += this.OnTargetDetached; } - private void OnTargetDetached(object sender, TargetDetachedEventArgs e) + private void OnTargetDetached(object? sender, TargetDetachedEventArgs e) { if (e.SessionId == this.ActiveSessionId && e.TargetId == this.attachedTargetId) { @@ -494,7 +491,7 @@ private async Task InitializeSocketConnection() LogTrace("Creating WebSocket"); this.connection = new WebSocketConnection(this.openConnectionWaitTimeSpan, this.closeConnectionWaitTimeSpan); connection.DataReceived += OnConnectionDataReceived; - await connection.Start(this.websocketAddress).ConfigureAwait(false); + await connection.Start(this.EndpointAddress).ConfigureAwait(false); LogTrace("WebSocket created"); } @@ -504,18 +501,18 @@ private async Task TerminateSocketConnection() if (this.connection != null && this.connection.IsActive) { await this.connection.Stop().ConfigureAwait(false); - await this.ShutdownMessageQueue().ConfigureAwait(false); + await this.ShutdownMessageQueue(this.connection).ConfigureAwait(false); } LogTrace("WebSocket closed"); } - private async Task ShutdownMessageQueue() + private async Task ShutdownMessageQueue(WebSocketConnection connection) { - // THe WebSockect connection is always closed before this method + // THe WebSocket connection is always closed before this method // is called, so there will eventually be no more data written // into the message queue, meaning this loop should be guaranteed // to complete. - while (this.connection.IsActive) + while (connection.IsActive) { await Task.Delay(TimeSpan.FromMilliseconds(10)); } @@ -534,7 +531,7 @@ private void MonitorMessageQueue() // in the IEnumerable, meaning the foreach loop will terminate gracefully. foreach (string message in this.messageQueue.GetConsumingEnumerable()) { - // Don't breake entire thread in case of unsuccessful message, + // Don't break entire thread in case of unsuccessful message, // and give a chance for the next message in queue to be processed try { @@ -544,10 +541,10 @@ private void MonitorMessageQueue() { if (logger.IsEnabled(LogEventLevel.Error)) { - logger.Error($"Unexpected error occured while processing message: {ex}"); + logger.Error($"Unexpected error occurred while processing message: {ex}"); } - LogError("Unexpected error occured while processing message: {0}", ex); + LogError("Unexpected error occurred while processing message: {0}", ex); } } } @@ -569,8 +566,7 @@ private void ProcessMessage(string message) { long commandId = idProperty.GetInt64(); - DevToolsCommandData commandInfo; - if (this.pendingCommands.TryGetValue(commandId, out commandInfo)) + if (this.pendingCommands.TryGetValue(commandId, out DevToolsCommandData? commandInfo)) { if (messageObject.TryGetProperty("error", out var errorProperty)) { @@ -580,7 +576,7 @@ private void ProcessMessage(string message) else { commandInfo.Result = messageObject.GetProperty("result"); - LogTrace("Recieved Response {0}: {1}", commandId, commandInfo.Result.ToString()); + LogTrace("Received Response {0}: {1}", commandId, commandInfo.Result.ToString()); } commandInfo.SyncEvent.Set(); @@ -589,10 +585,10 @@ private void ProcessMessage(string message) { if (logger.IsEnabled(LogEventLevel.Error)) { - logger.Error($"Recieved Unknown Response {commandId}: {message}"); + logger.Error($"Received Unknown Response {commandId}: {message}"); } - LogError("Recieved Unknown Response {0}: {1}", commandId, message); + LogError("Received Unknown Response {0}: {1}", commandId, message); } return; @@ -600,11 +596,11 @@ private void ProcessMessage(string message) if (messageObject.TryGetProperty("method", out var methodProperty)) { - var method = methodProperty.GetString(); + var method = methodProperty.GetString() ?? throw new InvalidOperationException("CDP message contained \"method\" property with a value of \"null\"."); var methodParts = method.Split(new char[] { '.' }, 2); var eventData = messageObject.GetProperty("params"); - LogTrace("Recieved Event {0}: {1}", method, eventData.ToString()); + LogTrace("Received Event {0}: {1}", method, eventData.ToString()); // Dispatch the event on a new thread so that any event handlers // responding to the event will not block this thread from processing @@ -621,7 +617,7 @@ private void ProcessMessage(string message) { if (logger.IsEnabled(LogEventLevel.Warn)) { - logger.Warn($"CDP VNT ^^ Unhandled error occured in event handler of '{method}' method. {ex}"); + logger.Warn($"CDP VNT ^^ Unhandled error occurred in event handler of '{method}' method. {ex}"); } throw; @@ -631,7 +627,7 @@ private void ProcessMessage(string message) return; } - LogTrace("Recieved Other: {0}", message); + LogTrace("Received Other: {0}", message); } private void OnDevToolsEventReceived(DevToolsEventReceivedEventArgs e) @@ -642,12 +638,12 @@ private void OnDevToolsEventReceived(DevToolsEventReceivedEventArgs e) } } - private void OnConnectionDataReceived(object sender, WebSocketConnectionDataReceivedEventArgs e) + private void OnConnectionDataReceived(object? sender, WebSocketConnectionDataReceivedEventArgs e) { this.messageQueue.Add(e.Data); } - private void LogTrace(string message, params object[] args) + private void LogTrace(string message, params object?[] args) { if (LogMessage != null) { @@ -655,7 +651,7 @@ private void LogTrace(string message, params object[] args) } } - private void LogError(string message, params object[] args) + private void LogError(string message, params object?[] args) { if (LogMessage != null) { diff --git a/dotnet/src/webdriver/DevTools/DevToolsSessionLogMessageEventArgs.cs b/dotnet/src/webdriver/DevTools/DevToolsSessionLogMessageEventArgs.cs index c2e233a695e2a..f11553a7eabdb 100644 --- a/dotnet/src/webdriver/DevTools/DevToolsSessionLogMessageEventArgs.cs +++ b/dotnet/src/webdriver/DevTools/DevToolsSessionLogMessageEventArgs.cs @@ -50,7 +50,7 @@ public class DevToolsSessionLogMessageEventArgs : EventArgs /// The level of the log message. /// The content of the log message. /// Arguments to be substituted when the message is formatted. - public DevToolsSessionLogMessageEventArgs(DevToolsSessionLogLevel level, string message, params object[] args) + public DevToolsSessionLogMessageEventArgs(DevToolsSessionLogLevel level, string message, params object?[] args) { Level = level; Message = string.Format(message, args); diff --git a/dotnet/src/webdriver/DevTools/DevToolsVersionInfo.cs b/dotnet/src/webdriver/DevTools/DevToolsVersionInfo.cs index 9b0314577c8e7..347ded9d45b1b 100644 --- a/dotnet/src/webdriver/DevTools/DevToolsVersionInfo.cs +++ b/dotnet/src/webdriver/DevTools/DevToolsVersionInfo.cs @@ -88,8 +88,7 @@ public string V8VersionNumber get { //Get the v8 version - var v8VersionRegex = new Regex(@"^(\d+)\.(\d+)\.(\d+)(\.\d+.*)?"); - var v8VersionMatch = v8VersionRegex.Match(V8Version); + var v8VersionMatch = Regex.Match(V8Version, @"^(\d+)\.(\d+)\.(\d+)(\.\d+.*)?"); if (v8VersionMatch.Success == false || v8VersionMatch.Groups.Count < 4) { throw new InvalidOperationException($"Unable to determine v8 version number from v8 version string ({V8Version})"); @@ -115,8 +114,7 @@ public string WebKitVersionHash get { //Get the webkit version hash. - var webkitVersionRegex = new Regex(@"\s\(@(\b[0-9a-f]{5,40}\b)"); - var webkitVersionMatch = webkitVersionRegex.Match(WebKitVersion); + var webkitVersionMatch = Regex.Match(WebKitVersion, @"\s\(@(\b[0-9a-f]{5,40}\b)"); if (webkitVersionMatch.Success == false || webkitVersionMatch.Groups.Count != 2) { throw new InvalidOperationException($"Unable to determine webkit version hash from webkit version string ({WebKitVersion})"); diff --git a/dotnet/src/webdriver/DevTools/IDevToolsSession.cs b/dotnet/src/webdriver/DevTools/IDevToolsSession.cs index 3837d38485523..9671da3d39780 100644 --- a/dotnet/src/webdriver/DevTools/IDevToolsSession.cs +++ b/dotnet/src/webdriver/DevTools/IDevToolsSession.cs @@ -23,6 +23,8 @@ using System.Threading; using System.Threading.Tasks; +#nullable enable + namespace OpenQA.Selenium.DevTools { /// @@ -34,18 +36,18 @@ public interface IDevToolsSession : IDisposable /// /// Event raised when the DevToolsSession logs informational messages. /// - event EventHandler LogMessage; + event EventHandler? LogMessage; /// /// Event raised an event notification is received from the DevTools session. /// - event EventHandler DevToolsEventReceived; + event EventHandler? DevToolsEventReceived; /// - /// Gets the domains that are valid for the specfied version of Developer Tools connection. + /// Gets the domains that are valid for the specified version of Developer Tools connection. /// /// - /// A type specific to the version of Develoepr Tools with which to communicate. + /// A type specific to the version of Developer Tools with which to communicate. /// /// The version-specific domains for this Developer Tools connection. T GetVersionSpecificDomains() where T : DevToolsSessionDomains; @@ -59,7 +61,7 @@ public interface IDevToolsSession : IDisposable /// The execution timeout of the command in milliseconds. /// to throw an exception if a response is not received; otherwise, . /// The command response object implementing the interface. - Task> SendCommand(TCommand command, CancellationToken cancellationToken, int? millisecondsTimeout, bool throwExceptionIfResponseNotReceived) + Task?> SendCommand(TCommand command, CancellationToken cancellationToken, int? millisecondsTimeout, bool throwExceptionIfResponseNotReceived) where TCommand : ICommand; /// @@ -72,7 +74,7 @@ Task> SendCommand(TCommand command, Cancell /// The execution timeout of the command in milliseconds. /// to throw an exception if a response is not received; otherwise, . /// The command response object implementing the interface. - Task SendCommand(TCommand command, CancellationToken cancellationToken, int? millisecondsTimeout, bool throwExceptionIfResponseNotReceived) + Task SendCommand(TCommand command, CancellationToken cancellationToken, int? millisecondsTimeout, bool throwExceptionIfResponseNotReceived) where TCommand : ICommand where TCommandResponse : ICommandResponse;