.NET automation layer for WebView2 JavaScript dialogs. Declarative policies for alert, confirm, and window.open, with embedded-window routing and a multi-WebView manager.
- .NET 10 or later
- Microsoft Edge WebView2 Runtime installed
- Windows (the library uses WinForms)
dotnet add package Carubbi.JavascriptWatcher
using Carubbi.JavascriptWatcher;
using Microsoft.Web.WebView2.WinForms;
WebView2 webView = ...;
var watcher = new JavascriptWatcher(webView);
watcher.AlertIntercepted += (s, e) => Console.WriteLine($"Alert: {e.Message}");
watcher.ConfirmIntercepted += (s, e) =>
{
Console.WriteLine($"Confirm: {e.Message}");
e.Result = true; // accept the confirm
};
watcher.WindowOpenIntercepted += (s, e) => Console.WriteLine($"Window open: {e.Url}");
watcher.Start(suppressAlert: true, suppressWindowOpen: true);Remove the if logic from your app by describing what to do per message/URL:
var alertPolicy = new AlertPolicy();
alertPolicy.WhenMessageMatches("session expired").Suppress();
alertPolicy.WhenSourceUrlMatches(@"https://app\.example\.com").Show();
var confirmPolicy = new ConfirmPolicy();
confirmPolicy.WhenMessageMatches(@"delete").AutoAccept();
confirmPolicy.WhenSourceUrlMatches(@"evil\.com").AutoReject();
var windowPolicy = new WindowOpenPolicy();
windowPolicy.WhenUrlMatches(@"docs\.example\.com").RouteTo(new WindowOpenTarget(docsPane));
windowPolicy.WhenUrlMatches(@"ads\.example\.com").Suppress();
windowPolicy.WhenUrlMatches(@"oauth\.").OpenExternally();
var watcher = new JavascriptWatcher(webView, alertPolicy, confirmPolicy, windowPolicy);
watcher.Start();Instead of opening an external popup, route the requested content into a docked WebView2 pane:
WindowOpenTarget docsPane = new(dockPane); // dockPane is a WebView2 control
var windowPolicy = new WindowOpenPolicy();
windowPolicy.WhenUrlMatches(@"^https://docs\.example\.com").RouteTo(docsPane);
var watcher = new JavascriptWatcher(webView, null, null, windowPolicy);
watcher.Start();One central policy applied to many controls:
var manager = new JavascriptWatcherManager(alertPolicy, confirmPolicy, windowPolicy);
manager.Add(webViewMain);
manager.Add(webViewAux);
// ...
manager.StopAll();Every dialog resolution is recorded through an IDialogAuditSink:
public sealed class TraceAuditSink : IDialogAuditSink
{
public void Record(DialogResolvedEventArgs e) =>
System.Diagnostics.Trace.WriteLine(
$"[{e.Timestamp:O}] {e.DialogType} -> {e.Decision?.Kind} | {e.Message} | {e.SourceUrl}");
}
var watcher = new JavascriptWatcher(webView, alertPolicy, confirmPolicy, windowPolicy, new TraceAuditSink());
watcher.Start();| Policy | Matcher | Decision |
|---|---|---|
AlertPolicy |
WhenMessageMatches, WhenSourceUrlMatches |
Suppress(), Show() |
ConfirmPolicy |
WhenMessageMatches, WhenSourceUrlMatches |
AutoAccept(), AutoReject() |
WindowOpenPolicy |
WhenUrlMatches |
RouteTo(target), Suppress(), OpenExternally() |
Policies are evaluated in registration order via IDialogPolicy.Evaluate(DialogContext). The first matching rule wins; otherwise the dialog passes through to the default browser behavior. Combine policies with CompositePolicy.
Unlike the old version (which injected JavaScript to override window.alert, window.confirm, and window.open in the DOM via MSHTML), version 3.x uses native WebView2 events:
ScriptDialogOpening— interceptsalert,confirm,prompt, andbeforeunloadNewWindowRequested— interceptswindow.open
No JavaScript is injected into the page, and no COM (MSHTML) reference is required.
v3.0.0 is a breaking release from v1; the v2 event API (Start/Stop + AlertIntercepted/ConfirmIntercepted/WindowOpenIntercepted) is preserved and v3 adds policies, routing, the manager, and auditing.
| v1.x | v3.x |
|---|---|
new JavascriptWatcher(WebBrowser) |
new JavascriptWatcher(WebView2) |
AlertInterceptedEventArgs.AlertText |
AlertInterceptedEventArgs.Message |
ConfirmInterceptedEventArgs.Text |
ConfirmInterceptedEventArgs.Message |
ScriptInterface (COM) |
Removed — native events |
AttachHandlers() |
Wired automatically in Start() |
| jQuery 1.11.1 injection | Removed |
Start(bool, bool) |
Plus Start() with declarative policies |
dotnet build Carubbi.JavascriptWatcher.slnx -c Release
dotnet run --project tests/Carubbi.JavascriptWatcher.Tests/Carubbi.JavascriptWatcher.Tests.csproj -c Release
powershell -File scripts/run-coverage.ps1 -Report -Open
Generates an HTML report at TestResults/coverage/html/index.html.
.github/workflows/ci.yml— build + tests on push/PR tomaster.github/workflows/publish.yml— pack + publish to NuGet.org when av*tag is created
MIT