All These Things That I've Done

Apply the programming model to everyday programming problems
posts - 83, comments - 71, trackbacks - 4

My Links

News


View Gianluca Carucci's profile on LinkedIn

Tag Cloud

Archives

Post Categories

Image Galleries

Blogs

Links

Testare classi che utilizzano Remoting

Problema: dobbiamo scrivere una serie di unit test che testano le funzionalità di un singleton pubblicato con Remoting.

Perchè è un problema? Perchè se specifico la porta usata dall'HttpChannel ed eseguo due test consecuitivi che registrano il nostro oggetto mediante l'httpchannel, il secondo test fallirà sempre. Il problema è dovuto al fatto che il socket del canale viene chiuso in maniera non determinstica (quando ne ha voglia il GC), quindi, quando viene eseguita (indirettamente dall'httpchannel) la bind per la seconda volta, viene lanciata un'eccezione che ci avverte che la porta tcp è già in uso ("only one usage of each socket address (protocol/IP address/port) is permitted"). 

Come risolverlo? Normalmente basterebbe chiudere il socket alla fine del test, peccato che l'httpchannel non fornisce nessuna reference al socket utlizzato e il channel non ha neanche un metodo Dispose che lo faccia indirettamente. Armato dei sani principi YAGNI e KISS, al posto di imbattermi in sinkprovider per cercare il socket perduto e chiuderlo a manina, ho trovato un piccolo workaround. La soluzione è banale, basta aprire l'httpchannel con il parametro port = 0. In questo modo, la porta del socket, viene scelta in modo automatico dal sistema (automatico=prima libera). A questo punto basta leggere la porta su cui ascolta il server ed usarla per creare il proxy. Ovviamente la porta scelta dinamicamente viene usata solo per i test, in produzione ha senso fissarne una decisa in fase di configurazione.

Ecco lo snippet di codice:
Creo il canale
HttpChannel channel = new HttpChannel(0);
ChannelServices.RegisterChannel(channel);

//Registro il servizio
RemoteConfiguration.RegisterWellKnownServiceType(typeof(Server), "MyService", WellKnownObjectMode.Singleton);
//Leggo l'indirizzo associato al servizio
string[] urls = channel.GetUrlsForUri("MyService");
int port = (new Uri(urls[0])).Port;

//Istanzio il proxy
IServer server = (IServer)Activator.GetObject(typeof(IServer), string.Format("http://localhost:/MyService", port));

Technorati tags:

Print | posted on martedì 20 dicembre 2005 17:24 | Filed Under [ C# ]

Powered by:
Powered By Subtext Powered By ASP.NET