venerdì 25 maggio 2007

.NET remoting ed eventi

E' da un po' che mi scontro con il problema sintetizzato in oggetto: come sottoscrivere un evento tra due istanze che vivono in due appDomain differenti.
Il meccanismo base non è doverso da una sottoscrizione "normale" tra due istanze che vivono nello stesso appDomain, ma c'è un elemento chiave che DEVE rimanere in testa (ed è quello che invece non mi rimane in testa al momento opportuno): il Garbage Collector NON tiene conto (non riesce credo..) dei "link" via remote.
Poniamo quindi di avere un appDomain1 con una istanza1 e un appDomain2 con una istanza2.
i due appDomain sono ovviamente raggiungibili via remoting.
L'istanza1 crea un delegate ad un proprio metodo e lo sottoscrive ad un evento dell'istanza2.
private void Subscribe()
{
istanza2.RemoteEvent += new EventhHandler(mio_metodo);
}
Come si può vedere l'istanza1 non tiene traccia del delegate che viene creato all'interno del metodo.
Il GC nota che non c'è nessun link a tale delegate e quindi lo rimuove.
Il risultato di tutto questo è che l'istanza1 riceverà notifica dell'evento dall' istanza2 fintanto che il GC non scatta nell'appDomain1. Dopo di che nell'istanza2, all'atto di lanciare l'evento si genererà una eccezzione del tipo "SocketException".

La soluzione è semplice: basta mantere il delegate in memoria nella istanza1, come nell'esempio sotto, e il GC non ce lo cancellerà:

private EventHandler delegate1;
private void Subscribe()
{
delegate1 =
EventhHandler(mio_metodo);
istanza2.RemoteEvent += delegate1
}

Per evitare malintesi voglio sottolineare che questo metodo non è legato in alcun modo al metodo InitializeLifetimeService() da overridare.
QUesto metodo deve essere sovrascritto nelle classi che derivano da MarhalByRefObject facendo in modo che restituisca null se si vuole che il il tempo che tale classe rimarrà attiva in remoto sia infinito, ci.
Un tipico override è:

public override object InitializeLifetimeService()
{
return null;
}

Nessun commento: