diff --git a/dotnet/src/webdriver/DriverService.cs b/dotnet/src/webdriver/DriverService.cs
index a8907cf976769..9aee2990b9f2f 100644
--- a/dotnet/src/webdriver/DriverService.cs
+++ b/dotnet/src/webdriver/DriverService.cs
@@ -176,33 +176,41 @@ protected virtual bool IsInitialized
{
get
{
- bool isInitialized = false;
+ return Task.Run(this.IsInitializedAsync).GetAwaiter().GetResult();
+ }
+ }
- try
+ ///
+ /// Gets a value indicating whether the service is responding to HTTP requests.
+ ///
+ /// A task that represents the asynchronous initialization check operation.
+ protected async virtual Task IsInitializedAsync()
+ {
+ bool isInitialized = false;
+ try
+ {
+ using (var httpClient = new HttpClient())
{
- using (var httpClient = new HttpClient())
- {
- httpClient.DefaultRequestHeaders.ConnectionClose = true;
- httpClient.Timeout = TimeSpan.FromSeconds(5);
+ httpClient.DefaultRequestHeaders.ConnectionClose = true;
+ httpClient.Timeout = TimeSpan.FromSeconds(5);
- Uri serviceHealthUri = new Uri(this.ServiceUrl, new Uri(DriverCommand.Status, UriKind.Relative));
- using (var response = Task.Run(async () => await httpClient.GetAsync(serviceHealthUri)).GetAwaiter().GetResult())
- {
- // Checking the response from the 'status' end point. Note that we are simply checking
- // that the HTTP status returned is a 200 status, and that the resposne has the correct
- // Content-Type header. A more sophisticated check would parse the JSON response and
- // validate its values. At the moment we do not do this more sophisticated check.
- isInitialized = response.StatusCode == HttpStatusCode.OK && response.Content.Headers.ContentType is { MediaType: string mediaType } && mediaType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase);
- }
+ Uri serviceHealthUri = new Uri(this.ServiceUrl, new Uri(DriverCommand.Status, UriKind.Relative));
+ using (var response = await httpClient.GetAsync(serviceHealthUri))
+ {
+ // Checking the response from the 'status' end point. Note that we are simply checking
+ // that the HTTP status returned is a 200 status, and that the response has the correct
+ // Content-Type header. A more sophisticated check would parse the JSON response and
+ // validate its values. At the moment we do not do this more sophisticated check.
+ isInitialized = response.StatusCode == HttpStatusCode.OK && response.Content.Headers.ContentType is { MediaType: string mediaType } && mediaType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase);
}
}
- catch (Exception ex) when (ex is HttpRequestException || ex is TaskCanceledException)
- {
- // Do nothing. The exception is expected, meaning driver service is not initialized.
- }
-
- return isInitialized;
}
+ catch (Exception ex) when (ex is HttpRequestException || ex is TaskCanceledException)
+ {
+ // Do nothing. The exception is expected, meaning driver service is not initialized.
+ }
+
+ return isInitialized;
}
///
@@ -217,39 +225,55 @@ public void Dispose()
///
/// Starts the DriverService if it is not already running.
///
- [MemberNotNull(nameof(driverServiceProcess))]
public void Start()
{
- if (this.driverServiceProcess != null)
- {
- return;
- }
-
- this.driverServiceProcess = new Process();
+ Task.Run(this.StartAsync).GetAwaiter().GetResult();
+ }
- if (this.DriverServicePath != null)
+ ///
+ /// Starts the DriverService if it is not already running.
+ ///
+ /// A task that represents the asynchronous start operation.
+ public async Task StartAsync()
+ {
+ if (this.driverServiceProcess == null)
{
- if (this.DriverServiceExecutableName is null)
+ this.driverServiceProcess = new Process();
+
+ try
{
- throw new InvalidOperationException("If the driver service path is specified, the driver service executable name must be as well");
- }
+ if (this.DriverServicePath != null)
+ {
+ if (this.DriverServiceExecutableName is null)
+ {
+ throw new InvalidOperationException("If the driver service path is specified, the driver service executable name must be as well");
+ }
- this.driverServiceProcess.StartInfo.FileName = Path.Combine(this.DriverServicePath, this.DriverServiceExecutableName);
- }
- else
- {
- this.driverServiceProcess.StartInfo.FileName = new DriverFinder(this.GetDefaultDriverOptions()).GetDriverPath();
- }
+ this.driverServiceProcess.StartInfo.FileName = Path.Combine(this.DriverServicePath, this.DriverServiceExecutableName);
+ }
+ else
+ {
+ this.driverServiceProcess.StartInfo.FileName = new DriverFinder(this.GetDefaultDriverOptions()).GetDriverPath();
+ }
- this.driverServiceProcess.StartInfo.Arguments = this.CommandLineArguments;
- this.driverServiceProcess.StartInfo.UseShellExecute = false;
- this.driverServiceProcess.StartInfo.CreateNoWindow = this.HideCommandPromptWindow;
+ this.driverServiceProcess.StartInfo.Arguments = this.CommandLineArguments;
+ this.driverServiceProcess.StartInfo.UseShellExecute = false;
+ this.driverServiceProcess.StartInfo.CreateNoWindow = this.HideCommandPromptWindow;
- DriverProcessStartingEventArgs eventArgs = new DriverProcessStartingEventArgs(this.driverServiceProcess.StartInfo);
- this.OnDriverProcessStarting(eventArgs);
+ DriverProcessStartingEventArgs eventArgs = new DriverProcessStartingEventArgs(this.driverServiceProcess.StartInfo);
+ this.OnDriverProcessStarting(eventArgs);
- this.driverServiceProcess.Start();
- bool serviceAvailable = this.WaitForServiceInitialization();
+ this.driverServiceProcess.Start();
+ }
+ catch
+ {
+ this.driverServiceProcess.Dispose();
+ this.driverServiceProcess = null;
+ throw;
+ }
+ }
+
+ bool serviceAvailable = await this.WaitForServiceInitializationAsync().ConfigureAwait(false);
DriverProcessStartedEventArgs processStartedEventArgs = new DriverProcessStartedEventArgs(this.driverServiceProcess);
this.OnDriverProcessStarted(processStartedEventArgs);
@@ -275,13 +299,33 @@ protected virtual void Dispose(bool disposing)
{
if (disposing)
{
- this.Stop();
+ Task.Run(this.StopAsync).GetAwaiter().GetResult();
}
this.isDisposed = true;
}
}
+ ///
+ /// Releases all resources associated with this .
+ ///
+ /// A task that represents the asynchronous dispose operation.
+ public async ValueTask DisposeAsync()
+ {
+ await DisposeAsyncCore();
+ Dispose(false);
+ GC.SuppressFinalize(this);
+ }
+
+ ///
+ /// Releases all resources associated with this type in the instance's type chain. Override to dispose more resources.
+ ///
+ /// A task that represents the asynchronous dispose operation.
+ protected virtual async ValueTask DisposeAsyncCore()
+ {
+ await this.StopAsync().ConfigureAwait(false);
+ }
+
///
/// Raises the event.
///
@@ -313,7 +357,7 @@ protected void OnDriverProcessStarted(DriverProcessStartedEventArgs eventArgs)
///
/// Stops the DriverService.
///
- private void Stop()
+ private async Task StopAsync()
{
if (this.IsRunning)
{
@@ -334,7 +378,7 @@ private void Stop()
// we'll retry. We wait for exit here, since catching the exception
// for a failed HTTP request due to a closed socket is particularly
// expensive.
- using (var response = Task.Run(async () => await httpClient.GetAsync(shutdownUrl)).GetAwaiter().GetResult())
+ using (var response = await httpClient.GetAsync(shutdownUrl).ConfigureAwait(false))
{
}
@@ -371,7 +415,7 @@ private void Stop()
///
/// if the service is properly started and receiving HTTP requests;
/// otherwise; .
- private bool WaitForServiceInitialization()
+ private async Task WaitForServiceInitializationAsync()
{
bool isInitialized = false;
DateTime timeout = DateTime.Now.Add(this.InitializationTimeout);
@@ -383,7 +427,7 @@ private bool WaitForServiceInitialization()
break;
}
- isInitialized = this.IsInitialized;
+ isInitialized = await this.IsInitializedAsync().ConfigureAwait(false);
}
return isInitialized;
diff --git a/dotnet/src/webdriver/Remote/DriverServiceCommandExecutor.cs b/dotnet/src/webdriver/Remote/DriverServiceCommandExecutor.cs
index 0f1d341c8c353..3f17f809cae2a 100644
--- a/dotnet/src/webdriver/Remote/DriverServiceCommandExecutor.cs
+++ b/dotnet/src/webdriver/Remote/DriverServiceCommandExecutor.cs
@@ -117,7 +117,7 @@ public async Task ExecuteAsync(Command commandToExecute)
Response toReturn;
if (commandToExecute.Name == DriverCommand.NewSession)
{
- this.service.Start();
+ await this.service.StartAsync().ConfigureAwait(false);
}
// Use a try-catch block to catch exceptions for the Quit