/// <summary> /// Execute a method call over the DevTools protocol. This method can be called on any thread. /// See the DevTools protocol documentation at https://chromedevtools.github.io/devtools-protocol/ for details /// of supported methods and the expected <paramref name="parameters"/> dictionary contents. /// </summary> /// <typeparam name="T">The type into which the result will be deserialzed.</typeparam> /// <param name="method">is the method name</param> /// <param name="parameters">are the method parameters represented as a dictionary, /// which may be empty.</param> /// <returns>return a Task that can be awaited to obtain the method result</returns> public Task <T> ExecuteDevToolsMethodAsync <T>(string method, IDictionary <string, object> parameters = null) where T : DevToolsDomainResponseBase { if (browser == null || browser.IsDisposed) { //TODO: Queue up commands where possible throw new ObjectDisposedException(nameof(IBrowser)); } var messageId = Interlocked.Increment(ref lastMessageId); var taskCompletionSource = new TaskCompletionSource <T>(); var methodResultContext = new DevToolsMethodResponseContext( type: typeof(T), setResult: o => taskCompletionSource.TrySetResult((T)o), setException: taskCompletionSource.TrySetException, syncContext: CaptureSyncContext ? SynchronizationContext.Current : SyncContext ); if (!queuedCommandResults.TryAdd(messageId, methodResultContext)) { throw new DevToolsClientException(string.Format("Unable to add MessageId {0} to queuedCommandResults ConcurrentDictionary.", messageId)); } var browserHost = browser.GetHost(); //Currently on CEF UI Thread we can directly execute if (CefThread.CurrentlyOnUiThread) { ExecuteDevToolsMethod(browserHost, messageId, method, parameters, methodResultContext); } //ExecuteDevToolsMethod can only be called on the CEF UI Thread else if (CefThread.CanExecuteOnUiThread) { CefThread.ExecuteOnUiThread(() => { ExecuteDevToolsMethod(browserHost, messageId, method, parameters, methodResultContext); return((object)null); }); } else { queuedCommandResults.TryRemove(messageId, out methodResultContext); throw new DevToolsClientException("Unable to invoke ExecuteDevToolsMethod on CEF UI Thread."); } return(taskCompletionSource.Task); }
private void ExecuteDevToolsMethod(IBrowserHost browserHost, int messageId, string method, IDictionary <string, object> parameters, DevToolsMethodResponseContext methodResultContext) { try { var returnedMessageId = browserHost.ExecuteDevToolsMethod(messageId, method, parameters); if (returnedMessageId == 0) { throw new DevToolsClientException(string.Format("Failed to execute dev tools method {0}.", method)); } else if (returnedMessageId != messageId) { //For some reason our message Id's don't match throw new DevToolsClientException(string.Format("Generated MessageId {0} doesn't match returned Message Id {1}", returnedMessageId, messageId)); } } catch (Exception ex) { queuedCommandResults.TryRemove(messageId, out _); methodResultContext.SetException(ex); } }