Aplicația dumneavoastră continuă să funcționeze în timp ce tunelul moare. Wi-Fi este încă activ, internetul încă răspunde, iar API-ul privat de care depinde aplicația a devenit inaccesibil. Evenimentul .NET la care oamenii apelează de obicei aici, NetworkAvailabilityChanged, nu descrie deloc acea situație. El raportează o schimbare a stării agregate a mașinii, iar acea stare poate rămâne adevărată pe parcursul deconectării și reconectării VPN. Un observator trebuie să urmărească clientul care deține tunelul, nu rezumatul stivei de rețea.

Disponibilitatea este un agregat, nu tunelul dumneavoastră

NetworkAvailabilityChanged se declanșează când răspunsul agregat de disponibilitate al mașinii se schimbă, iar acel răspuns numără orice interfață activă, în afară de loopback sau un tunel.

O cădere a VPN cu Wi-Fi activ nu schimbă nimic din ce măsoară, de aceea evenimentul poate rămâne tăcut exact în timpul defecțiunii care vă interesează.

Fluxul de stare aparține clientului care deține tunelul

Identificați ce componentă deține conexiunea: GUI-ul sau serviciul OpenVPN, OpenVPN Connect, sau un proces pe care aplicația dumneavoastră l-a pornit și îl controlează. Aceștia sunt proprietari diferiți cu interfețe acceptate diferite, iar observatorul trebuie să o folosească pe cea care corespunde implementării. Pentru un proces OpenVPN cu care sunteți autorizat să vă integrați, interfața de administrare raportează starea curentă, un istoric și notificări în timp real. Analizați mesajele structurate documentate în loc să căutați cuvântul connected într-o legendă de GUI localizată.

Canalul de administrare este o suprafață de control privilegiată, așa că nu deschideți un ascultător nou și nu vă certați cu GUI-ul pentru un canal pe care îl deține deja.

Protecțiile de generație opresc rezultatele învechite

Fiecare observație aparține unei anumite încercări de conectare. Incrementați un contor de generație când începe o încercare nouă, când canalul se pierde și când clientul raportează ieșirea.

Luați în considerare o sondare începută în timpul conexiunii A. Tunelul cade, conexiunea B începe, iar apoi sosește succesul HTTP întârziat al lui A. Fără o protecție, acel rezultat vechi face afișajul verde în timp ce B încă se autentifică. Anularea reduce munca irosită, iar verificarea generației este cea care împiedică o finalizare învechită să devină starea curentă:

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

Aplicați aceeași regulă în jurul trimiterii către UI, deoarece actualizarea marshallată poate sosi după ce generația a avansat.

Inițializarea și reconectarea sunt un singur ciclu de viață

Tratați prima conectare, reconectarea și pierderea canalului ca un singur ciclu de viață cu un singur set de reguli:

  • Citiți starea curentă și abonați-vă la notificări într-un singur pas, acolo unde interfața permite.
  • Etichetați fiecare observație cu identitatea conexiunii și generația.
  • Invalidați disponibilitatea la reconectare, ieșire sau la un canal de observare pierdut.
  • Sondați resursa privată doar după ce proprietarul raportează că inițializarea s-a încheiat.
  • Publicați doar rezultatele care aparțin încă generației curente.

Un canal pierdut înseamnă necunoscut, nu deconectat. Raportarea necunoscutului este mai onestă decât raportarea unei deconectări pe care nu o puteți dovedi și împiedică logica de reîncercare să acționeze pe baza unei presupuneri.

Raportați dovezi, nu un boolean

Returnați starea de sesiune numită și disponibilitatea resursei ca valori separate, fiecare cu o vârstă. Un consumator care trebuie să decidă ceva poate vedea atunci că ultima sondare reușită are patruzeci de secunde, ceea ce este o informație diferită de una proaspătă.

O căutare de IP public nu este dovada că un API privat a folosit ruta cerută, așa că nu o prezentați ca și cum ar fi.

Țineți aplicarea în afara observatorului

Un callback rulează după fapt. Nu poate garanta că niciun pachet nu a părăsit mașina între eveniment și handler. Dacă designul cere blocare, politica de rețea trebuie să o ofere, iar sarcina observatorului este să explice dovezile apelantului său. Amestecarea celor două produce cod care se crede firewall pentru că ține un boolean. Țineți stratul de aplicare plictisitor și testabil, iar observatorul să rămână cititor.

Atunci întrebarea despre UI devine simplă: arătați ce se știe, împreună cu vârsta, și spuneți necunoscut când este cazul.

Articole similare