Skip to content

Commit e23507e

Browse files
authored
[dotnet] Any WebDriver can be disposed asynchronously (SeleniumHQ#17119)
1 parent 2f71272 commit e23507e

File tree

10 files changed

+127
-42
lines changed

10 files changed

+127
-42
lines changed

dotnet/src/support/BUILD.bazel

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ load(
33
"csharp_library",
44
"generated_assembly_info",
55
"nuget_pack",
6+
"nuget_package",
67
)
78
load(
89
"//dotnet:selenium-dotnet-version.bzl",
@@ -44,6 +45,8 @@ csharp_library(
4445
],
4546
deps = [
4647
"//dotnet/src/webdriver:webdriver-netstandard2.0",
48+
nuget_package("Microsoft.Bcl.AsyncInterfaces"),
49+
nuget_package("System.Threading.Tasks.Extensions"),
4750
],
4851
)
4952

@@ -84,6 +87,8 @@ csharp_library(
8487
],
8588
deps = [
8689
"//dotnet/src/webdriver:webdriver-netstandard2.0-strongnamed",
90+
nuget_package("Microsoft.Bcl.AsyncInterfaces"),
91+
nuget_package("System.Threading.Tasks.Extensions"),
8792
],
8893
)
8994

dotnet/src/support/Events/EventFiringWebDriver.cs

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,38 @@ public void Dispose()
405405
GC.SuppressFinalize(this);
406406
}
407407

408+
/// <summary>
409+
/// Asynchronously disposes this instance.
410+
/// </summary>
411+
/// <returns>A task representing the asynchronous dispose operation.</returns>
412+
public async ValueTask DisposeAsync()
413+
{
414+
await this.DisposeAsyncCore().ConfigureAwait(false);
415+
this.Dispose(false);
416+
GC.SuppressFinalize(this);
417+
}
418+
419+
/// <summary>
420+
/// Stops the client from running.
421+
/// </summary>
422+
/// <param name="disposing">If <see langword="true"/>, managed resources are disposed.</param>
423+
protected virtual void Dispose(bool disposing)
424+
{
425+
if (disposing)
426+
{
427+
WrappedDriver.Dispose();
428+
}
429+
}
430+
431+
/// <summary>
432+
/// Asynchronously performs the core dispose logic.
433+
/// </summary>
434+
/// <returns>A task representing the asynchronous dispose operation.</returns>
435+
protected virtual async ValueTask DisposeAsyncCore()
436+
{
437+
await WrappedDriver.DisposeAsync().ConfigureAwait(false);
438+
}
439+
408440
/// <summary>
409441
/// Executes JavaScript in the context of the currently selected frame or window.
410442
/// </summary>
@@ -580,19 +612,6 @@ public Screenshot GetScreenshot()
580612
return screenshotDriver.GetScreenshot();
581613
}
582614

583-
/// <summary>
584-
/// Frees all managed and, optionally, unmanaged resources used by this instance.
585-
/// </summary>
586-
/// <param name="disposing"><see langword="true"/> to dispose of only managed resources;
587-
/// <see langword="false"/> to dispose of managed and unmanaged resources.</param>
588-
protected virtual void Dispose(bool disposing)
589-
{
590-
if (disposing)
591-
{
592-
this.WrappedDriver.Dispose();
593-
}
594-
}
595-
596615
/// <summary>
597616
/// Raises the <see cref="Navigating"/> event.
598617
/// </summary>

dotnet/src/webdriver/Chromium/ChromiumDriver.cs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -480,9 +480,9 @@ public void StopCasting(string deviceName)
480480
}
481481

482482
/// <summary>
483-
/// Stops the driver from running
483+
/// Disposes of the resources used by the <see cref="ChromiumDriver"/> instance, including any active DevTools session.
484484
/// </summary>
485-
/// <param name="disposing">if its in the process of disposing</param>
485+
/// <param name="disposing">Indicates whether the method is being called from a Dispose method (true) or from a finalizer (false).</param>
486486
protected override void Dispose(bool disposing)
487487
{
488488
if (disposing)
@@ -497,6 +497,21 @@ protected override void Dispose(bool disposing)
497497
base.Dispose(disposing);
498498
}
499499

500+
/// <summary>
501+
/// Asynchronously disposes of the resources used by the <see cref="ChromiumDriver"/> instance, including any active DevTools session.
502+
/// </summary>
503+
/// <returns>A task representing the asynchronous dispose operation.</returns>
504+
protected override async ValueTask DisposeAsyncCore()
505+
{
506+
if (this.devToolsSession != null)
507+
{
508+
this.devToolsSession.Dispose();
509+
this.devToolsSession = null;
510+
}
511+
512+
await base.DisposeAsyncCore().ConfigureAwait(false);
513+
}
514+
500515
private static ICapabilities ConvertOptionsToCapabilities(ChromiumOptions options)
501516
{
502517
if (options == null)

dotnet/src/webdriver/Firefox/FirefoxDriver.cs

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -414,17 +414,6 @@ protected virtual void PrepareEnvironment()
414414
// Does nothing, but provides a hook for subclasses to do "stuff"
415415
}
416416

417-
/// <summary>
418-
/// Disposes of the FirefoxDriver and frees all resources.
419-
/// </summary>
420-
/// <param name="disposing">A value indicating whether the user initiated the
421-
/// disposal of the object. Pass <see langword="true"/> if the user is actively
422-
/// disposing the object; otherwise <see langword="false"/>.</param>
423-
protected override void Dispose(bool disposing)
424-
{
425-
base.Dispose(disposing);
426-
}
427-
428417
private static ICapabilities ConvertOptionsToCapabilities(FirefoxOptions options)
429418
{
430419
if (options == null)

dotnet/src/webdriver/IWebDriver.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ namespace OpenQA.Selenium;
4343
/// more fully featured browser when there is a requirement for one.
4444
/// </para>
4545
/// </remarks>
46-
public interface IWebDriver : ISearchContext, IDisposable
46+
public interface IWebDriver : ISearchContext, IDisposable, IAsyncDisposable
4747
{
4848
/// <summary>
4949
/// Gets or sets the URL the browser is currently displaying.

dotnet/src/webdriver/WebDriver.cs

Lines changed: 59 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,17 @@ public void Dispose()
223223
GC.SuppressFinalize(this);
224224
}
225225

226+
/// <summary>
227+
/// Asynchronously disposes the WebDriver Instance
228+
/// </summary>
229+
/// <returns>A task representing the asynchronous dispose operation.</returns>
230+
public async ValueTask DisposeAsync()
231+
{
232+
await this.DisposeAsyncCore().ConfigureAwait(false);
233+
this.Dispose(false);
234+
GC.SuppressFinalize(this);
235+
}
236+
226237
/// <summary>
227238
/// Executes JavaScript "asynchronously" in the context of the currently selected frame or window,
228239
/// 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
672683
/// <param name="disposing">if its in the process of disposing</param>
673684
protected virtual void Dispose(bool disposing)
674685
{
675-
try
686+
if (disposing)
676687
{
677688
if (this.SessionId is not null)
678689
{
679-
this.Execute(DriverCommand.Quit, null);
690+
try
691+
{
692+
693+
this.Execute(DriverCommand.Quit, null);
694+
695+
}
696+
catch (NotImplementedException)
697+
{
698+
}
699+
catch (InvalidOperationException)
700+
{
701+
}
702+
catch (WebDriverException)
703+
{
704+
}
705+
finally
706+
{
707+
this.SessionId = null!;
708+
}
680709
}
710+
711+
this.CommandExecutor.Dispose();
681712
}
682-
catch (NotImplementedException)
683-
{
684-
}
685-
catch (InvalidOperationException)
686-
{
687-
}
688-
catch (WebDriverException)
689-
{
690-
}
691-
finally
713+
}
714+
715+
/// <summary>
716+
/// Asynchronously performs the core dispose logic.
717+
/// </summary>
718+
/// <returns>A task representing the asynchronous dispose operation.</returns>
719+
protected virtual async ValueTask DisposeAsyncCore()
720+
{
721+
if (this.SessionId is not null)
692722
{
693-
this.SessionId = null!;
723+
try
724+
{
725+
await this.ExecuteAsync(DriverCommand.Quit, null).ConfigureAwait(false);
726+
}
727+
catch (NotImplementedException)
728+
{
729+
}
730+
catch (InvalidOperationException)
731+
{
732+
}
733+
catch (WebDriverException)
734+
{
735+
}
736+
finally
737+
{
738+
this.SessionId = null!;
739+
}
694740
}
695741

696742
this.CommandExecutor.Dispose();

dotnet/src/webdriver/assets/nuget/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Selenium is a set of different software tools each with a different approach to
66
using OpenQA.Selenium.Chrome;
77
using OpenQA.Selenium;
88

9-
using var driver = new ChromeDriver();
9+
await using var driver = new ChromeDriver();
1010

1111
driver.Url = "https://www.google.com";
1212
driver.FindElement(By.Name("q")).SendKeys("webdriver" + Keys.Return);

dotnet/test/common/StubDriver.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
using System;
2121
using System.Collections.ObjectModel;
22+
using System.Threading.Tasks;
2223

2324
namespace OpenQA.Selenium;
2425

@@ -101,4 +102,13 @@ public void Dispose()
101102
}
102103

103104
#endregion
105+
106+
#region IAsyncDisposable Members
107+
108+
public ValueTask DisposeAsync()
109+
{
110+
throw new NotImplementedException();
111+
}
112+
113+
#endregion
104114
}

dotnet/test/support/Events/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ dotnet_nunit_test_suite(
1313
"//dotnet/src/support",
1414
"//dotnet/src/webdriver:webdriver-net8.0",
1515
"//dotnet/test/common:fixtures",
16+
nuget_package("Microsoft.Bcl.AsyncInterfaces"),
1617
nuget_package("NUnit"),
1718
nuget_package("Moq"),
1819
],

dotnet/test/support/Selenium.WebDriver.Support.Tests.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@
66
</PropertyGroup>
77

88
<ItemGroup>
9+
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="8.0.0" />
910
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" />
1011
<PackageReference Include="Moq" Version="4.20.72" />
1112
<PackageReference Include="NUnit" Version="3.14.0" />
1213
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0" />
1314
</ItemGroup>
1415

1516
<ItemGroup>
16-
<ProjectReference Include="..\..\src\webdriver\Selenium.WebDriver.csproj" />
1717
<ProjectReference Include="..\..\src\support\Selenium.WebDriver.Support.csproj" />
1818
<ProjectReference Include="..\common\Selenium.WebDriver.Common.Tests.csproj" />
1919
</ItemGroup>

0 commit comments

Comments
 (0)