private async Task CloseCoreAsync() { try { try { // Initiate graceful browser close operation but don't await it just yet, // because we want to ensure chromium process shutdown first. var browserCloseTask = Connection.IsClosed ? Task.CompletedTask : Connection.SendAsync("Browser.close", null); if (ChromiumProcess != null) { // Notify chromium process that exit is expected, but should be enforced if it // doesn't occur withing the close timeout. var closeTimeout = TimeSpan.FromMilliseconds(CloseTimeout); await ChromiumProcess.EnsureExitAsync(closeTimeout).ConfigureAwait(false); } // Now we can safely await the browser close operation without risking keeping chromium // process running for indeterminate period. await browserCloseTask.ConfigureAwait(false); } finally { Disconnect(); } } catch (Exception ex) { _logger.LogError(ex, ex.Message); if (ChromiumProcess != null) { await ChromiumProcess.KillAsync().ConfigureAwait(false); } } // Ensure that remaining targets are always marked closed, so that asynchronous page close // operations on any associated pages don't get blocked. foreach (var target in TargetsMap.Values) { target.CloseTaskWrapper.TrySetResult(false); } Closed?.Invoke(this, new EventArgs()); }
private async Task CloseCoreAsync() { try { try { // Initiate graceful browser close operation but don't await it just yet, // because we want to ensure chromium process shutdown first. var browserCloseTask = Connection.SendAsync("Browser.close", null); if (_chromiumProcess != null) { // Notify chromium process that exit is expected, but should be enforced if it // doesn't occur withing the close timeout. var closeTimeout = TimeSpan.FromMilliseconds(CloseTimeout); await _chromiumProcess.EnsureExitAsync(closeTimeout).ConfigureAwait(false); } // Now we can safely await the browser close operation without risking keeping chromium // process running for indeterminate period. await browserCloseTask.ConfigureAwait(false); } finally { Disconnect(); } } catch (Exception ex) { _logger.LogError(ex, ex.Message); if (_chromiumProcess != null) { await _chromiumProcess.KillAsync().ConfigureAwait(false); } } Closed?.Invoke(this, new EventArgs()); }
/// <summary> /// The method launches a browser instance with given arguments. The browser will be closed when the Browser is disposed. /// </summary> /// <param name="options">Options for launching Chrome</param> /// <returns>A connected browser.</returns> /// <remarks> /// See <a href="https://www.howtogeek.com/202825/what%E2%80%99s-the-difference-between-chromium-and-chrome/">this article</a> /// for a description of the differences between Chromium and Chrome. /// <a href="https://chromium.googlesource.com/chromium/src/+/lkcr/docs/chromium_browser_vs_google_chrome.md">This article</a> describes some differences for Linux users. /// </remarks> public async Task <Browser> LaunchAsync(LaunchOptions options) { EnsureSingleLaunchOrConnect(); var chromiumExecutable = GetOrFetchChromeExecutable(options); Process = new ChromiumProcess(chromiumExecutable, options, _loggerFactory); try { await Process.StartAsync().ConfigureAwait(false); try { var connection = await Connection .Create(Process.EndPoint, options, _loggerFactory) .ConfigureAwait(false); var browser = await Browser .CreateAsync(connection, Array.Empty <string>(), options.IgnoreHTTPSErrors, options.DefaultViewport, Process) .ConfigureAwait(false); await EnsureInitialPageAsync(browser).ConfigureAwait(false); return(browser); } catch (Exception ex) { throw new ChromiumProcessException("Failed to create connection", ex); } } catch { await Process.KillAsync().ConfigureAwait(false); throw; } }