From 2c037640627f8d058336f0e54ec64b0b066b3aa5 Mon Sep 17 00:00:00 2001
From: Nikolay Borisenko <22616990+nvborisenko@users.noreply.github.com>
Date: Wed, 18 Feb 2026 23:26:09 +0300
Subject: [PATCH 1/4] Start session async
---
dotnet/src/webdriver/WebDriver.cs | 31 +++++++++++++++++++++----------
1 file changed, 21 insertions(+), 10 deletions(-)
diff --git a/dotnet/src/webdriver/WebDriver.cs b/dotnet/src/webdriver/WebDriver.cs
index 78c76f08ebadb..32991250039a6 100644
--- a/dotnet/src/webdriver/WebDriver.cs
+++ b/dotnet/src/webdriver/WebDriver.cs
@@ -88,7 +88,7 @@ protected WebDriver(ICommandExecutor executor, ICapabilities capabilities)
///
/// Gets the that the driver session was created with, which may be different from those requested.
///
- public ICapabilities Capabilities { get; private set; }
+ public ICapabilities Capabilities { get; private set; } = null!;
///
/// Gets or sets the URL the browser is currently displaying.
@@ -180,7 +180,7 @@ public ReadOnlyCollection WindowHandles
///
/// Gets the for the current session of this driver.
///
- public SessionId SessionId { get; private set; }
+ public SessionId SessionId { get; private set; } = null!;
///
/// Gets or sets the responsible for detecting
@@ -584,11 +584,20 @@ protected internal virtual async Task ExecuteAsync(string driverComman
/// Starts a session with the driver
///
/// Capabilities of the browser
- [MemberNotNull(nameof(SessionId))]
- [MemberNotNull(nameof(Capabilities))]
protected void StartSession(ICapabilities capabilities)
{
- Dictionary parameters = new Dictionary();
+ Task.Run(() => this.StartSessionAsync(capabilities)).GetAwaiter().GetResult();
+ }
+
+ ///
+ /// Asynchronously starts a session with the driver.
+ ///
+ /// Capabilities of the browser.
+ /// A task that represents the asynchronous operation.
+ /// If the session cannot be started or the response is invalid.
+ protected async Task StartSessionAsync(ICapabilities capabilities)
+ {
+ Dictionary parameters = [];
// If the object passed into the RemoteWebDriver constructor is a
// RemoteSessionSettings object, it is expected that all intermediate
@@ -599,11 +608,12 @@ protected void StartSession(ICapabilities capabilities)
{
Dictionary matchCapabilities = this.GetCapabilitiesDictionary(capabilities);
- List firstMatchCapabilitiesList = new List();
- firstMatchCapabilitiesList.Add(matchCapabilities);
+ List firstMatchCapabilitiesList = [matchCapabilities];
- Dictionary specCompliantCapabilitiesDictionary = new Dictionary();
- specCompliantCapabilitiesDictionary["firstMatch"] = firstMatchCapabilitiesList;
+ Dictionary specCompliantCapabilitiesDictionary = new()
+ {
+ ["firstMatch"] = firstMatchCapabilitiesList
+ };
parameters.Add("capabilities", specCompliantCapabilitiesDictionary);
}
@@ -612,9 +622,10 @@ protected void StartSession(ICapabilities capabilities)
parameters.Add("capabilities", remoteSettings.ToDictionary());
}
- Response response = this.Execute(DriverCommand.NewSession, parameters);
+ Response response = await this.ExecuteAsync(DriverCommand.NewSession, parameters).ConfigureAwait(false);
response.EnsureValueIsNotNull();
+
if (response.Value is not Dictionary rawCapabilities)
{
string errorMessage = string.Format(CultureInfo.InvariantCulture, "The new session command returned a value ('{0}') that is not a valid JSON object.", response.Value);
From 863eec43791c9fc9d7ac5978e94a6a418fe1a23f Mon Sep 17 00:00:00 2001
From: Nikolay Borisenko <22616990+nvborisenko@users.noreply.github.com>
Date: Wed, 18 Feb 2026 23:37:29 +0300
Subject: [PATCH 2/4] Flag to autostart session
---
dotnet/src/webdriver/WebDriver.cs | 34 ++++++++++++++++++++++---------
1 file changed, 24 insertions(+), 10 deletions(-)
diff --git a/dotnet/src/webdriver/WebDriver.cs b/dotnet/src/webdriver/WebDriver.cs
index 32991250039a6..f94a578306f4b 100644
--- a/dotnet/src/webdriver/WebDriver.cs
+++ b/dotnet/src/webdriver/WebDriver.cs
@@ -48,6 +48,17 @@ public class WebDriver : IWebDriver, ISearchContext, IJavaScriptExecutor, IFinds
/// The object used to execute commands.
/// The object used to configure the driver session.
protected WebDriver(ICommandExecutor executor, ICapabilities capabilities)
+ : this(executor, capabilities, true)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The object used to execute commands.
+ /// The object used to configure the driver session.
+ /// Whether to automatically start the driver session.
+ protected WebDriver(ICommandExecutor executor, ICapabilities capabilities, bool autoStartSession)
{
this.CommandExecutor = executor;
this.elementFactory = new WebElementFactory(this);
@@ -61,22 +72,25 @@ protected WebDriver(ICommandExecutor executor, ICapabilities capabilities)
this.RegisterDriverCommand(DriverCommand.GetLog, new HttpCommandInfo(HttpCommandInfo.PostCommand, "/session/{sessionId}/se/log"), true);
}
- try
- {
- this.StartSession(capabilities);
- }
- catch (Exception)
+ if (autoStartSession)
{
try
{
- // Failed to start driver session, disposing of driver
- this.Dispose();
+ this.StartSession(capabilities);
}
- catch
+ catch (Exception)
{
- // Ignore the clean-up exception. We'll propagate the original failure.
+ try
+ {
+ // Failed to start driver session, disposing of driver
+ this.Dispose();
+ }
+ catch
+ {
+ // Ignore the clean-up exception. We'll propagate the original failure.
+ }
+ throw;
}
- throw;
}
}
From c4b6bf9d4b310dd0bfdeae4993777842bd22fb7b Mon Sep 17 00:00:00 2001
From: Nikolay Borisenko <22616990+nvborisenko@users.noreply.github.com>
Date: Wed, 18 Feb 2026 23:44:24 +0300
Subject: [PATCH 3/4] Docs
---
dotnet/src/webdriver/WebDriver.cs | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/dotnet/src/webdriver/WebDriver.cs b/dotnet/src/webdriver/WebDriver.cs
index f94a578306f4b..27583a06c10f2 100644
--- a/dotnet/src/webdriver/WebDriver.cs
+++ b/dotnet/src/webdriver/WebDriver.cs
@@ -43,7 +43,7 @@ public class WebDriver : IWebDriver, ISearchContext, IJavaScriptExecutor, IFinds
private readonly List registeredCommands = new List();
///
- /// Initializes a new instance of the class.
+ /// Initializes a new instance of the class and automatically starts the driver session.
///
/// The object used to execute commands.
/// The object used to configure the driver session.
@@ -53,11 +53,11 @@ protected WebDriver(ICommandExecutor executor, ICapabilities capabilities)
}
///
- /// Initializes a new instance of the class.
+ /// Initializes a new instance of the class with optional automatic session initialization.
///
/// The object used to execute commands.
/// The object used to configure the driver session.
- /// Whether to automatically start the driver session.
+ /// Whether to automatically start the driver session. When , the session is started immediately; when , the session must be started manually.
protected WebDriver(ICommandExecutor executor, ICapabilities capabilities, bool autoStartSession)
{
this.CommandExecutor = executor;
From 6a74f0305c83f37c1744cd92e478322e3dc44c14 Mon Sep 17 00:00:00 2001
From: Nikolay Borisenko <22616990+nvborisenko@users.noreply.github.com>
Date: Thu, 19 Feb 2026 00:24:27 +0300
Subject: [PATCH 4/4] Start Async!
---
dotnet/src/webdriver/Chrome/ChromeDriver.cs | 55 +++++++++++++++++++
.../src/webdriver/Chromium/ChromiumDriver.cs | 24 +++++++-
2 files changed, 78 insertions(+), 1 deletion(-)
diff --git a/dotnet/src/webdriver/Chrome/ChromeDriver.cs b/dotnet/src/webdriver/Chrome/ChromeDriver.cs
index 80108a05187ff..ae8619f11d75d 100644
--- a/dotnet/src/webdriver/Chrome/ChromeDriver.cs
+++ b/dotnet/src/webdriver/Chrome/ChromeDriver.cs
@@ -157,6 +157,61 @@ public ChromeDriver(ChromeDriverService service, ChromeOptions options, TimeSpan
this.AddCustomChromeCommands();
}
+ ///
+ /// Initializes a new instance of the class using the specified command executor and options.
+ ///
+ /// The to use for executing commands.
+ /// The to use for this driver.
+ /// Whether to automatically start the session.
+ protected ChromeDriver(ICommandExecutor commandExecutor, ChromeOptions options, bool autoStartSession)
+ : base(commandExecutor, options, autoStartSession)
+ {
+ if (autoStartSession)
+ {
+ this.AddCustomChromeCommands();
+ }
+ }
+
+ ///
+ /// Asynchronously creates and starts a new instance of the class with default options.
+ ///
+ /// A task that represents the asynchronous operation. The task result contains the initialized .
+ public static Task StartAsync()
+ {
+ return StartAsync(new ChromeOptions());
+ }
+
+ ///
+ /// Asynchronously creates and starts a new instance of the class using the specified options.
+ ///
+ /// The to be used with the Chrome driver.
+ /// A task that represents the asynchronous operation. The task result contains the initialized .
+ /// If is .
+ public static async Task StartAsync(ChromeOptions options)
+ {
+ if (options is null)
+ {
+ throw new ArgumentNullException(nameof(options), "Chrome options must not be null");
+ }
+
+ ChromeDriverService service = ChromeDriverService.CreateDefaultService();
+ ICommandExecutor executor = await GenerateDriverServiceCommandExecutorAsync(service, options, DefaultCommandTimeout).ConfigureAwait(false);
+
+ ChromeDriver driver = new(executor, options, autoStartSession: false);
+ driver.AddCustomChromeCommands();
+
+ try
+ {
+ await driver.StartSessionAsync(options.ToCapabilities()).ConfigureAwait(false);
+ return driver;
+ }
+ catch
+ {
+ driver.Dispose();
+ throw;
+ }
+ }
+
///
/// Gets a read-only dictionary of the custom WebDriver commands defined for ChromeDriver.
/// The keys of the dictionary are the names assigned to the command; the values are the
diff --git a/dotnet/src/webdriver/Chromium/ChromiumDriver.cs b/dotnet/src/webdriver/Chromium/ChromiumDriver.cs
index 8857f5229b254..e9be48602a7e4 100644
--- a/dotnet/src/webdriver/Chromium/ChromiumDriver.cs
+++ b/dotnet/src/webdriver/Chromium/ChromiumDriver.cs
@@ -132,6 +132,20 @@ protected ChromiumDriver(ChromiumDriverService service, ChromiumOptions options,
this.optionsCapabilityName = options.CapabilityName ?? throw new ArgumentException("No chromium options capability name specified", nameof(options));
}
+ ///
+ /// Initializes a new instance of the class using the specified command executor and options.
+ ///
+ /// The to use for executing commands.
+ /// The to be used with the ChromiumDriver.
+ /// Whether to automatically start the session.
+ /// If is .
+ /// If the Chromium options capability name is .
+ protected ChromiumDriver(ICommandExecutor commandExecutor, ChromiumOptions options, bool autoStartSession)
+ : base(commandExecutor, ConvertOptionsToCapabilities(options), autoStartSession)
+ {
+ this.optionsCapabilityName = options.CapabilityName ?? throw new ArgumentException("No chromium options capability name specified", nameof(options));
+ }
+
///
/// Gets the dictionary of custom Chromium commands registered with the driver.
///
@@ -144,7 +158,15 @@ await GenerateDriverServiceCommandExecutorAsync(service, options, commandTimeout
.GetAwaiter().GetResult();
}
- private static async Task GenerateDriverServiceCommandExecutorAsync(DriverService service, DriverOptions options, TimeSpan commandTimeout)
+ ///
+ /// Asynchronously generates a driver service command executor.
+ ///
+ /// The to use.
+ /// The to be used with the driver.
+ /// The maximum amount of time to wait for each command.
+ /// A task that represents the asynchronous operation. The task result contains the .
+ /// If or are .
+ protected static async Task GenerateDriverServiceCommandExecutorAsync(DriverService service, DriverOptions options, TimeSpan commandTimeout)
{
if (service is null)
{