/// <summary> /// Executes a method call over the DevTools protocol. /// </summary> /// <param name="webview">The WebView control.</param> /// <param name="method">The method name.</param> /// <param name="parameters"> /// The JSON string with method parameters. May be null. /// See the <see href="https://chromedevtools.github.io/devtools-protocol/"> /// DevTools Protocol documentation</see> for details of supported methods /// and the expected parameters. /// </param> /// <param name="cancellationToken">The token to monitor for cancellation requests.</param> /// <returns> /// The JSON string with the response. Structure of the response varies depending /// on the method name and is defined by the 'RETURN OBJECT' section of /// the Chrome DevTools Protocol command description. /// </returns> /// <remarks> /// Usage of the ExecuteDevToolsMethodAsync function does not require an active /// DevTools front-end or remote-debugging session. Other active DevTools sessions /// will continue to function independently. However, any modification of global /// browser state by one session may not be reflected in the UI of other sessions. /// <para/> /// Communication with the DevTools front-end (when displayed) can be logged /// for development purposes by passing the `--devtools-protocol-log- /// file=<path>` command-line flag. /// </remarks> public static Task<string> ExecuteDevToolsMethodAsync(this IChromiumWebView webview, string method, string parameters, CancellationToken cancellationToken) { CefValue args = null; if (parameters != null) { args = CefApi.CefParseJSON(parameters, CefJsonParserOptions.AllowTrailingCommas, out string errorMessage); if (args is null) throw new ArgumentOutOfRangeException(nameof(parameters), errorMessage is null ? "An error occurred during JSON parsing." : errorMessage); } return ExecuteDevToolsMethodAsync(webview, method, args is null ? default(CefDictionaryValue) : args.GetDictionary(), cancellationToken); }
private static async Task<string> ExecuteDevToolsMethodInternalAsync(IChromiumWebView webview, string method, CefDictionaryValue parameters, CancellationToken cancellationToken) { CefBrowser browser = webview.BrowserObject; if (browser is null) throw new InvalidOperationException(); cancellationToken.ThrowIfCancellationRequested(); CefBrowserHost browserHost = browser.Host; DevToolsProtocolClient protocolClient = GetProtocolClient(browserHost); await CefNetSynchronizationContextAwaiter.GetForThread(CefThreadId.UI); cancellationToken.ThrowIfCancellationRequested(); int messageId = browserHost.ExecuteDevToolsMethod(protocolClient.IncrementMessageId(), method, parameters); protocolClient.UpdateLastMessageId(messageId); DevToolsMethodResult r; if (cancellationToken.CanBeCanceled) { Task<DevToolsMethodResult> waitTask = protocolClient.WaitForMessageAsync(messageId, DevToolsCallCompletionSource.ConvertUtf8BufferToJsonString); await Task.WhenAny(waitTask, Task.Delay(Timeout.Infinite, cancellationToken)).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); r = waitTask.Result; } else { r = await protocolClient.WaitForMessageAsync(messageId, DevToolsCallCompletionSource.ConvertUtf8BufferToJsonString).ConfigureAwait(false); } if (r.Success) { if (r.Result is byte[] buff) return Encoding.UTF8.GetString(buff); return r.Result as string; } CefValue errorValue; if (r.Result is byte[] buffer) errorValue = CefApi.CefParseJSONBuffer(buffer, CefJsonParserOptions.AllowTrailingCommas); else errorValue = CefApi.CefParseJSON(r.Result as string, CefJsonParserOptions.AllowTrailingCommas); if (errorValue is null) throw new DevToolsProtocolException($"An unknown error occurred while trying to execute the '{method}' method."); throw new DevToolsProtocolException(errorValue.GetDictionary().GetString("message")); }