diff --git a/dotnet/src/support/BUILD.bazel b/dotnet/src/support/BUILD.bazel index b4251681c8452..19d8a5d896384 100644 --- a/dotnet/src/support/BUILD.bazel +++ b/dotnet/src/support/BUILD.bazel @@ -3,6 +3,7 @@ load( "csharp_library", "generated_assembly_info", "nuget_pack", + "nuget_package", ) load( "//dotnet:selenium-dotnet-version.bzl", @@ -44,6 +45,8 @@ csharp_library( ], deps = [ "//dotnet/src/webdriver:webdriver-netstandard2.0", + nuget_package("Microsoft.Bcl.AsyncInterfaces"), + nuget_package("System.Threading.Tasks.Extensions"), ], ) @@ -84,6 +87,8 @@ csharp_library( ], deps = [ "//dotnet/src/webdriver:webdriver-netstandard2.0-strongnamed", + nuget_package("Microsoft.Bcl.AsyncInterfaces"), + nuget_package("System.Threading.Tasks.Extensions"), ], ) diff --git a/dotnet/src/support/Events/EventFiringWebDriver.cs b/dotnet/src/support/Events/EventFiringWebDriver.cs index 70b69589f7500..9933064e8871f 100644 --- a/dotnet/src/support/Events/EventFiringWebDriver.cs +++ b/dotnet/src/support/Events/EventFiringWebDriver.cs @@ -405,6 +405,38 @@ public void Dispose() GC.SuppressFinalize(this); } + /// + /// Asynchronously disposes this instance. + /// + /// A task representing the asynchronous dispose operation. + public async ValueTask DisposeAsync() + { + await this.DisposeAsyncCore().ConfigureAwait(false); + this.Dispose(false); + GC.SuppressFinalize(this); + } + + /// + /// Stops the client from running. + /// + /// If , managed resources are disposed. + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + WrappedDriver.Dispose(); + } + } + + /// + /// Asynchronously performs the core dispose logic. + /// + /// A task representing the asynchronous dispose operation. + protected virtual async ValueTask DisposeAsyncCore() + { + await WrappedDriver.DisposeAsync().ConfigureAwait(false); + } + /// /// Executes JavaScript in the context of the currently selected frame or window. /// @@ -580,19 +612,6 @@ public Screenshot GetScreenshot() return screenshotDriver.GetScreenshot(); } - /// - /// Frees all managed and, optionally, unmanaged resources used by this instance. - /// - /// to dispose of only managed resources; - /// to dispose of managed and unmanaged resources. - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - this.WrappedDriver.Dispose(); - } - } - /// /// Raises the event. /// diff --git a/dotnet/src/webdriver/Chromium/ChromiumDriver.cs b/dotnet/src/webdriver/Chromium/ChromiumDriver.cs index 8857f5229b254..71f864f771513 100644 --- a/dotnet/src/webdriver/Chromium/ChromiumDriver.cs +++ b/dotnet/src/webdriver/Chromium/ChromiumDriver.cs @@ -480,9 +480,9 @@ public void StopCasting(string deviceName) } /// - /// Stops the driver from running + /// Disposes of the resources used by the instance, including any active DevTools session. /// - /// if its in the process of disposing + /// Indicates whether the method is being called from a Dispose method (true) or from a finalizer (false). protected override void Dispose(bool disposing) { if (disposing) @@ -497,6 +497,21 @@ protected override void Dispose(bool disposing) base.Dispose(disposing); } + /// + /// Asynchronously disposes of the resources used by the instance, including any active DevTools session. + /// + /// A task representing the asynchronous dispose operation. + protected override async ValueTask DisposeAsyncCore() + { + if (this.devToolsSession != null) + { + this.devToolsSession.Dispose(); + this.devToolsSession = null; + } + + await base.DisposeAsyncCore().ConfigureAwait(false); + } + private static ICapabilities ConvertOptionsToCapabilities(ChromiumOptions options) { if (options == null) diff --git a/dotnet/src/webdriver/Firefox/FirefoxDriver.cs b/dotnet/src/webdriver/Firefox/FirefoxDriver.cs index 0573d2ed368e7..fd4d58c049eb5 100644 --- a/dotnet/src/webdriver/Firefox/FirefoxDriver.cs +++ b/dotnet/src/webdriver/Firefox/FirefoxDriver.cs @@ -414,17 +414,6 @@ protected virtual void PrepareEnvironment() // Does nothing, but provides a hook for subclasses to do "stuff" } - /// - /// Disposes of the FirefoxDriver and frees all resources. - /// - /// A value indicating whether the user initiated the - /// disposal of the object. Pass if the user is actively - /// disposing the object; otherwise . - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - } - private static ICapabilities ConvertOptionsToCapabilities(FirefoxOptions options) { if (options == null) diff --git a/dotnet/src/webdriver/IWebDriver.cs b/dotnet/src/webdriver/IWebDriver.cs index 7a92363acbaa3..9177ae81098a1 100644 --- a/dotnet/src/webdriver/IWebDriver.cs +++ b/dotnet/src/webdriver/IWebDriver.cs @@ -43,7 +43,7 @@ namespace OpenQA.Selenium; /// more fully featured browser when there is a requirement for one. /// /// -public interface IWebDriver : ISearchContext, IDisposable +public interface IWebDriver : ISearchContext, IDisposable, IAsyncDisposable { /// /// Gets or sets the URL the browser is currently displaying. diff --git a/dotnet/src/webdriver/WebDriver.cs b/dotnet/src/webdriver/WebDriver.cs index 78c76f08ebadb..0df8343313859 100644 --- a/dotnet/src/webdriver/WebDriver.cs +++ b/dotnet/src/webdriver/WebDriver.cs @@ -223,6 +223,17 @@ public void Dispose() GC.SuppressFinalize(this); } + /// + /// Asynchronously disposes the WebDriver Instance + /// + /// A task representing the asynchronous dispose operation. + public async ValueTask DisposeAsync() + { + await this.DisposeAsyncCore().ConfigureAwait(false); + this.Dispose(false); + GC.SuppressFinalize(this); + } + /// /// Executes JavaScript "asynchronously" in the context of the currently selected frame or window, /// executing the callback function specified as the last argument in the list of arguments. @@ -672,25 +683,60 @@ protected bool RegisterInternalDriverCommand(string commandName, [NotNullWhen(tr /// if its in the process of disposing protected virtual void Dispose(bool disposing) { - try + if (disposing) { if (this.SessionId is not null) { - this.Execute(DriverCommand.Quit, null); + try + { + + this.Execute(DriverCommand.Quit, null); + + } + catch (NotImplementedException) + { + } + catch (InvalidOperationException) + { + } + catch (WebDriverException) + { + } + finally + { + this.SessionId = null!; + } } + + this.CommandExecutor.Dispose(); } - catch (NotImplementedException) - { - } - catch (InvalidOperationException) - { - } - catch (WebDriverException) - { - } - finally + } + + /// + /// Asynchronously performs the core dispose logic. + /// + /// A task representing the asynchronous dispose operation. + protected virtual async ValueTask DisposeAsyncCore() + { + if (this.SessionId is not null) { - this.SessionId = null!; + try + { + await this.ExecuteAsync(DriverCommand.Quit, null).ConfigureAwait(false); + } + catch (NotImplementedException) + { + } + catch (InvalidOperationException) + { + } + catch (WebDriverException) + { + } + finally + { + this.SessionId = null!; + } } this.CommandExecutor.Dispose(); diff --git a/dotnet/src/webdriver/assets/nuget/README.md b/dotnet/src/webdriver/assets/nuget/README.md index e780243d3445b..e05cb38ab350b 100644 --- a/dotnet/src/webdriver/assets/nuget/README.md +++ b/dotnet/src/webdriver/assets/nuget/README.md @@ -6,7 +6,7 @@ Selenium is a set of different software tools each with a different approach to using OpenQA.Selenium.Chrome; using OpenQA.Selenium; -using var driver = new ChromeDriver(); +await using var driver = new ChromeDriver(); driver.Url = "https://www.google.com"; driver.FindElement(By.Name("q")).SendKeys("webdriver" + Keys.Return); diff --git a/dotnet/test/common/StubDriver.cs b/dotnet/test/common/StubDriver.cs index 9f14206c40196..64d6cfa821fa4 100644 --- a/dotnet/test/common/StubDriver.cs +++ b/dotnet/test/common/StubDriver.cs @@ -19,6 +19,7 @@ using System; using System.Collections.ObjectModel; +using System.Threading.Tasks; namespace OpenQA.Selenium; @@ -101,4 +102,13 @@ public void Dispose() } #endregion + + #region IAsyncDisposable Members + + public ValueTask DisposeAsync() + { + throw new NotImplementedException(); + } + + #endregion } diff --git a/dotnet/test/support/Events/BUILD.bazel b/dotnet/test/support/Events/BUILD.bazel index 060534a69a7bc..593314776f691 100644 --- a/dotnet/test/support/Events/BUILD.bazel +++ b/dotnet/test/support/Events/BUILD.bazel @@ -13,6 +13,7 @@ dotnet_nunit_test_suite( "//dotnet/src/support", "//dotnet/src/webdriver:webdriver-net8.0", "//dotnet/test/common:fixtures", + nuget_package("Microsoft.Bcl.AsyncInterfaces"), nuget_package("NUnit"), nuget_package("Moq"), ], diff --git a/dotnet/test/support/Selenium.WebDriver.Support.Tests.csproj b/dotnet/test/support/Selenium.WebDriver.Support.Tests.csproj index be6aaef57a009..036e08d4bfd77 100644 --- a/dotnet/test/support/Selenium.WebDriver.Support.Tests.csproj +++ b/dotnet/test/support/Selenium.WebDriver.Support.Tests.csproj @@ -6,6 +6,7 @@ + @@ -13,7 +14,6 @@ -