Votre application continue de fonctionner pendant que le tunnel meurt. Le Wi-Fi est toujours actif, Internet répond encore, et l'API privée dont dépend l'application est devenue inaccessible. L'événement .NET vers lequel on se tourne généralement ici, NetworkAvailabilityChanged, ne décrit pas du tout cette situation. Il signale un changement de l'état agrégé de la machine, et cet état peut rester vrai pendant une déconnexion et une reconnexion VPN. Un observateur doit surveiller le client qui possède le tunnel, pas le résumé de la pile réseau.

La disponibilité est un agrégat, pas votre tunnel

NetworkAvailabilityChanged se déclenche lorsque la réponse agrégée de disponibilité de la machine change, et cette réponse compte toute interface active autre que loopback ou un tunnel.

Une coupure VPN alors que le Wi-Fi est actif ne change rien à ce qu'elle mesure, c'est pourquoi l'événement peut rester silencieux pendant précisément la panne qui vous importe.

Le flux d'état appartient au client qui possède le tunnel

Identifiez quel composant possède la connexion : l'interface graphique ou le service OpenVPN, OpenVPN Connect, ou un processus que votre application a lancé et contrôle. Ce sont des propriétaires différents avec des interfaces prises en charge différentes, et l'observateur doit utiliser celle qui correspond au déploiement. Pour un processus OpenVPN avec lequel vous êtes autorisé à vous intégrer, l'interface de gestion rapporte l'état courant, un historique et des notifications en temps réel. Analysez les messages structurés documentés au lieu de chercher le mot connected dans une légende d'interface localisée.

Le canal de gestion est une surface de contrôle privilégiée, donc n'ouvrez pas un nouvel écouteur et ne vous battez pas avec l'interface graphique pour un canal qu'elle détient déjà.

Les gardes de génération arrêtent les résultats périmés

Chaque observation appartient à une tentative de connexion précise. Incrémentez un compteur de génération lorsqu'une nouvelle tentative démarre, lorsque le canal est perdu et lorsque le client signale une sortie.

Considérez une sonde lancée pendant la connexion A. Le tunnel tombe, la connexion B commence, puis le succès HTTP retardé de A arrive. Sans garde, cet ancien résultat rend l'affichage vert alors que B s'authentifie encore. L'annulation réduit le travail inutile, et la vérification de génération est ce qui empêche un achèvement périmé de devenir l'état courant :

var generation = _generation;
var reachable = await ProbeAsync(token);
if (generation != _generation) return;
Publish(reachable);

Appliquez la même règle autour de l'envoi vers l'interface, car la mise à jour marshallée peut arriver après que la génération a avancé.

L'initialisation et la reconnexion sont un seul cycle de vie

Traitez la première connexion, la reconnexion et la perte de canal comme un seul cycle de vie avec un seul ensemble de règles :

  • Lisez l'état courant et abonnez-vous aux notifications en une seule étape là où l'interface le permet.
  • Marquez chaque observation avec l'identité de la connexion et la génération.
  • Invalidez la disponibilité lors d'une reconnexion, d'une sortie ou d'un canal d'observation perdu.
  • Sondez la ressource privée seulement après que le propriétaire signale l'initialisation terminée.
  • Ne publiez que les résultats qui appartiennent encore à la génération courante.

Un canal perdu signifie inconnu, pas déconnecté. Signaler l'inconnu est plus honnête que de signaler une déconnexion que vous ne pouvez pas prouver, et cela empêche la logique de nouvelle tentative d'agir sur une supposition.

Rapportez des preuves, pas un booléen

Renvoyez l'état de session nommé et la disponibilité de la ressource comme des valeurs distinctes, chacune portant un âge. Un consommateur qui doit décider quelque chose peut alors voir que la dernière sonde réussie a quarante secondes, ce qui est une information différente d'une information fraîche.

Une recherche d'IP publique n'est pas la preuve qu'une API privée a utilisé la route requise, donc ne la présentez pas comme telle.

Gardez l'application en dehors de l'observateur

Un rappel s'exécute après coup. Il ne peut pas garantir qu'aucun paquet n'a quitté la machine entre l'événement et le gestionnaire. Si la conception exige un blocage, la politique réseau doit le fournir, et le rôle de l'observateur est d'expliquer les preuves à son appelant. Mélanger les deux produit du code qui croit être un pare-feu parce qu'il détient un booléen. Gardez la couche d'application ennuyeuse et testable, et laissez l'observateur rester un lecteur.

Alors la question de l'interface devient simple : montrez ce qui est connu, avec son âge, et dites inconnu quand cela l'est.

Articles similaires