Jeg sidder på en server applikation, der rejser en række events, som et ukendt antal klienter kan abonnerer på. Så begynder jeg pludselig at få periodiske fejl – der er klienter der ikke bliver notificeret når serveren rejser en event. Efter lang tids debugging, finder jeg frem til problemet. En af klienterne, smider en Exception i EventHandleren som den har føjet til observer listen (hooket op på eventen).
Per design fungerer MulticastDelegate således at den har en intern liste (invocationlist), som indeholder en reference til alle de eventhandlere der er tilføjet til den. Når man så f.eks. rejser eventen:
Change(this, EventArgs.Empty)
Så bliver hver enkelt eventhandler kaldt synkront fra en ende af. Hvis man så, som i mit tilfælde, har en af disse eventhandlere der smider en uhåndteret Exception, så stopper den sekventielle eksekvering af listen, og man kommer ikke videre.
Man skal altså sørge for at metoder der implementerer en delegate, på ingen måde kan smide en Exception. Men hvad nu hvis man ikke har styr på alle observanter, og ikke har mulighed for at sikre den kvalitet?
Jeg har forsøgt med følgende fejlsikre metode:
protected void OnChange(EventArgs args)
{
foreach (EventHandler item in Change.GetInvocationList())
{
try
{
item.Invoke(this, args);
}
catch(Exception){}
}
}
Her bruger jeg MulticastDelegate.GetInvocationList() til at få en array af delegates der er registreret som lytterere på eventen, og kalder derefter hver delegate en efter en, og sikre mig at vi kommer videre selvom der sker fejl.
Det virker, og jeg er sluppet for fejl, men er det en ok løsning?
Kan man eventuelt udnytte samme princip til at udfører koden asynkront?
Altså bruge BeginInvoke i stedet for Invoke?
Det kræver flere tests, men jeg tror jeg har fat i noget…
Code on…