WebView2 : Gérer Les Événements DevToolsProtocolEvent En C# WPF
Salut les développeurs ! Vous vous arrachez les cheveux avec WebView2 et les événements DevToolsProtocolEvent en C# WPF ? Vous n'êtes pas seuls, mes amis. Beaucoup d'entre nous se retrouvent bloqués quand il s'agit de capturer ces précieuses informations, comme les logs JavaScript via console.log(). C'est un peu comme essayer d'attraper des lucioles dans le noir, hein ? Mais pas de panique, on va démystifier tout ça ensemble. Imaginez que vous construisez une application super cool en WPF, et au cœur de celle-ci, un composant WebView2 qui affiche des pages web. Le rêve, non ? Sauf que voilà, vous voulez absolument récupérer ce qui se passe dans la console du site web, ces petits messages que les développeurs web jettent là avec console.log(), console.warn(), ou pire, console.error(). Ces infos, c'est de l'or ! Elles peuvent vous aider à débugger, à comprendre le comportement d'une page, bref, à rendre votre application encore plus robuste. Mais comment faire ? C'est là qu'intervient le fameux Chrome DevTools Protocol (CDP), et plus spécifiquement, comment interagir avec lui depuis notre bon vieux C# WPF via WebView2. Ne vous laissez pas intimider par le nom barbare, c'est votre meilleur ami pour ce genre de tâche. On va plonger dans les détails pour que vous puissiez, comme moi, enfin faire remonter ces messages et erreurs comme un chef !
Comprendre le Chrome DevTools Protocol et WebView2
Alors, les gars, pour vraiment maîtriser les événements DevToolsProtocolEvent dans WebView2 avec C# WPF, il faut d'abord piger deux-trois trucs sur le Chrome DevTools Protocol. Pensez-y comme à un super-pouvoir que Microsoft a donné à WebView2. En gros, WebView2 utilise le moteur Chromium (le même que Google Chrome, ouais !), et Chromium expose une interface hyper puissante : le CDP. Ce protocole, c'est une API de type JSON qui permet de contrôler et d'inspecter le navigateur de manière programmatique. Vous pouvez faire tout un tas de choses avec : naviguer, prendre des screenshots, injecter du JavaScript, et surtout, interagir avec la console du développeur. C'est exactement ce qui nous intéresse pour capturer les console.log(). Quand on parle de DevToolsProtocolEvent, on parle des événements qui vous sont envoyés depuis le moteur Chromium vers votre application WPF, via WebView2. C'est un flux d'informations en temps réel. L'idée, c'est que votre application WPF écoute ces événements. Mais attention, le CDP, c'est pas une mince affaire. Il y a des tonnes de commandes et d'événements disponibles. Pour notre besoin, on va se concentrer sur le domaine Runtime, qui gère l'exécution du code JavaScript. Plus précisément, on va s'intéresser à l'événement Console.messageAdded. C'est exactement ça qu'il nous faut pour récupérer les logs. Notre défi, c'est de configurer WebView2 pour qu'il nous écoute sur cet événement spécifique, et de savoir comment interpréter les données qu'il nous envoie. Il ne suffit pas d'activer le CDP, il faut aussi s'abonner aux bons événements. Souvent, le piège est là : on croit que le simple fait d'avoir le contrôle du DevTools suffit, mais il faut explicitement demander à recevoir les notifications de console. C'est un peu comme ouvrir la porte mais ne pas tendre l'oreille. Pour ça, on utilise la méthode AddScriptToExecuteOnDocumentCreatedAsync ou des techniques similaires pour s'assurer que le CDP est bien prêt à communiquer dès le chargement de la page. Ensuite, c'est l'abonnement aux événements qui compte. Dans le cadre de WebView2, l'objet CoreWebView2 expose la propriété DevToolsProtocolEventReceived. C'est via cette propriété que votre application C# va recevoir les données du CDP. Il faut donc attacher un handler à cet événement. Ce handler recevra un objet contenant le RawData (les données brutes du protocole) et le WebMessageEventKind (qui nous dit de quel type d'événement il s'agit). Pour les logs de console, le RawData sera un JSON représentant l'événement Console.messageAdded. Vous devrez ensuite désérialiser ce JSON pour en extraire le message, le niveau (log, warning, error), et d'autres infos utiles. La clé, c'est de comprendre cette communication bidirectionnelle : vous envoyez des commandes au navigateur via le CDP, et il vous renvoie des événements en retour. C'est ce mécanisme qu'on va exploiter.
Implémenter la capture des logs JavaScript avec C# WPF
Ok, les potos, passons à la partie concrète : comment on fait pour que ça marche, ce truc de capture de logs JavaScript en C# WPF avec WebView2 ? Vous avez compris que le Chrome DevTools Protocol (CDP) est notre arme secrète. La première étape, les gars, c'est de s'assurer que WebView2 est prêt et que le CDP est activé. Souvent, vous créez votre contrôle Microsoft.Web.WebView2.Wpf.WebView2 dans votre XAML, et dans votre code-behind (souvent dans le OnNavigated ou le CoreWebView2InitializationCompleted), vous allez initialiser WebView2. C'est là qu'il faut s'assurer que le CDP est accessible. La méthode clé est EnsureCoreWebView2Async. Une fois que vous avez votre CoreWebView2 (appelons-le webView.CoreWebView2), vous pouvez commencer à jouer avec le CDP. Pour écouter les messages de la console, on va s'abonner à l'événement DevToolsProtocolEventReceived. C'est crucial, mettez un post-it dessus ! Voici à quoi ça peut ressembler :
webView.CoreWebView2.DevToolsProtocolEventReceived += CoreWebView2_DevToolsProtocolEventReceived;
Ce CoreWebView2_DevToolsProtocolEventReceived est la méthode qui va être appelée chaque fois que le navigateur nous envoie une notification via le CDP. Mais attention, ça ne suffit pas ! Il faut demander au navigateur de nous envoyer les événements de console. Comment ? En envoyant une commande CDP spécifique pour s'abonner. La commande est Runtime.enable. On peut l'envoyer une fois que le CoreWebView2 est prêt, généralement après l'initialisation.
await webView.CoreWebView2.Runtime.EnableCommandAsync();
Ceci active le domaine Runtime du CDP, ce qui nous permet de recevoir des événements comme Console.messageAdded. Maintenant, dans notre gestionnaire CoreWebView2_DevToolsProtocolEventReceived, on va recevoir un objet DevToolsProtocolEventArgs. Ce qui nous intéresse, c'est la propriété RawData. C'est une chaîne JSON qui contient l'événement. Pour les logs console, ce JSON ressemble typiquement à ça :
{
"method": "Runtime.messageAdded",
"params": {
"message": {
"source": "javascript",
"level": "log", // ou 'warning', 'error', 'info', 'debug'
"text": "Mon message de log JS",
"url": "...",
"line": 10,
"column": 5
}
}
}
Notre boulot, c'est de prendre cette chaîne RawData, de vérifier si method est bien "Runtime.messageAdded", et si oui, de désérialiser le params.message en un objet C# que l'on aura défini. Vous pouvez utiliser System.Text.Json ou Newtonsoft.Json pour ça. Il faut créer des classes C# qui correspondent à la structure du JSON. Par exemple :
public class ConsoleMessage
{
public string Source { get; set; }
public string Level { get; set; } // Utilisez une énumération pour les niveaux
public string Text { get; set; }
public string Url { get; set; }
public int Line { get; set; }
public int Column { get; set; }
}
public class DevToolsMessage
{
public string Method { get; set; }
public dynamic Params { get; set; } // Ou des classes plus spécifiques
}
Dans votre gestionnaire d'événements, vous allez donc faire quelque chose comme ça :
private void CoreWebView2_DevToolsProtocolEventReceived(object sender, Microsoft.Web.WebView2.Core.CoreWebView2DevToolsProtocolEventArgs e)
{
if (e.RawData != null)
{
var rawJson = System.Text.Json.JsonDocument.Parse(e.RawData);
var rootElement = rawJson.RootElement;
if (rootElement.TryGetProperty("method", out var methodElement) && methodElement.GetString() == "Runtime.messageAdded")
{
if (rootElement.TryGetProperty("params", out var paramsElement) && paramsElement.TryGetProperty("message", out var messageElement))
{
var message = messageElement.Deserialize<ConsoleMessage>();
// Maintenant, faites ce que vous voulez avec 'message.Text', 'message.Level', etc.
// Par exemple, affichez-le dans une TextBox ou enregistrez-le.
Console.WriteLine({{content}}quot;[{message.Level}] {message.Text}");
}
}
}
}
N'oubliez pas d'importer les bons namespaces et de gérer les erreurs potentielles (par exemple, si le JSON n'est pas valide ou si les propriétés attendues sont manquantes). C'est vraiment cette combinaison : s'abonner à DevToolsProtocolEventReceived, activer le domaine Runtime avec Runtime.enable, et parser le JSON reçu qui va vous permettre de pister ces logs JavaScript. Simple, mais sacrément efficace quand on sait comment faire !
Bonnes pratiques et gestion des erreurs
Alright les amis, maintenant que vous savez comment faire tekniquement, parlons des bonnes pratiques et de la gestion des erreurs quand on manipule les événements DevToolsProtocolEvent de WebView2 en C# WPF. C'est super important, parce que dans le monde réel, les choses ne se passent pas toujours comme prévu, hein ? Premièrement, l'initialisation asynchrone est votre meilleure amie. Rappelez-vous, EnsureCoreWebView2Async renvoie une tâche. Ne bloquez surtout pas le thread UI en attendant qu'elle se termine ! Utilisez await correctement dans une méthode async pour maintenir votre application réactive. Si vous gérez l'initialisation dans le constructeur ou un événement qui ne supporte pas async void, vous pouvez utiliser ContinueWith avec TaskScheduler.FromCurrentSynchronizationContext() pour vous assurer que les callbacks s'exécutent sur le bon thread. Ensuite, parlons de la robustesse de votre gestionnaire d'événements. Le JSON que vous recevez du CDP peut parfois être inattendu. Assurez-vous que votre code de désérialisation est résistant. Utilisez TryGetProperty au lieu d'accéder directement aux propriétés pour éviter les exceptions si une clé manque. Préférez des classes de modèles spécifiques plutôt que dynamic si possible, car cela rend votre code plus sûr et plus facile à maintenir. Définissez des énumérations pour les niveaux de log ('log', 'warning', 'error', etc.) au lieu d'utiliser des chaînes brutes. Ça évite les fautes de frappe et rend votre code plus lisible. Pensez aussi à la gestion des erreurs de communication. Que se passe-t-il si le CDP se déconnecte ou si une commande échoue ? Vous devriez envisager d'ajouter des blocs try-catch autour des appels de commande CDP et potentiellement des mécanismes de reconnexion ou de notification à l'utilisateur si la communication échoue. Le DevToolsProtocolEventReceived peut aussi être déclenché pour d'autres événements que Runtime.messageAdded. Votre code doit donc ignorer les événements qui ne vous intéressent pas. Une simple vérification de la propriété method suffit généralement. Un autre point crucial : le nettoyage. Lorsque votre WebView2 est détruit (par exemple, lorsque la fenêtre de votre application se ferme), vous devez vous désabonner de tous les événements auxquels vous vous êtes abonnés pour éviter les fuites de mémoire. N'oubliez pas de faire webView.CoreWebView2.DevToolsProtocolEventReceived -= CoreWebView2_DevToolsProtocolEventReceived; dans le bon événement de cycle de vie de votre contrôle ou fenêtre (comme Closing ou Unloaded). Pensez aussi à la performance. Si le site web génère une quantité énorme de logs, votre gestionnaire d'événements pourrait devenir un goulot d'étranglement. Si c'est le cas, envisagez de traiter les messages dans un thread séparé ou d'implémenter une forme de limitation de débit (throttling). Et enfin, une astuce de pro : utilisez le Console.Clear() de votre application hôte si vous voulez vider la