Domani sera terremo il secondo meeting del semestre, presso il Novotel di Mestre (Viale Ceccherini), e spero di vedervi numerosi, magari anche oltre i più di 50 che hanno preannunciato la propria partecipazione sul nostro sito.

Lorenzo e Davide parleranno per le consuete 3 ore di Team Foundation Server in due sessioni che abbracciano gli aspetti più innovativi come il supporto ai database e gli aspetti metodologici con una sessione su Scrum.

La serata anche questa volta non è supportata da alcuno sponsor. Perciò se per caso ritenete che la nostra attività abbia un qualche significato per voi, il vostro lavoro o la vostra passione allora prendete in considerazione di avvicinarmi e pronunciare la fatidica frase "vorrei iscrivermi"...

Vi assicuro che se ci avete pensato almeno una volta, questa occasione è davvero la migliore possibile, non fosse altro che investendo i 50 euro della quota per il 2010... potreste portare a casa qualcosa di eccezionale... e non dico altro :)

A domani... anzi, a stasera :)


windows2008logoDopo un paio di serate di lavoro ho concluso il ripristino del mio portatile sul quale ho installato Windows Server 2008.

Devo dire che ora che ho sistemato tutto a dovere, i risultati sono eccellenti. La macchina ha guadagnato in velocità in modo più che apprezzabile, e non ho perso nulla rispetto a Windows Vista se escludiamo, unico caso isolato, il ReadyBoost.

Ho installato e attivato tutto, Aero, Sidebar, Gadgets, etc... ed è rimasta anche qualche feature poco user friendly tipica di Vista. Se qualcuno avesse intenzione di tentare questo stesso passaggio consiglio di usare il seguente sito come guida per il setup:

http://www.win2008workstation.com/

Le cose da tarare sono molte, e non tutto è semplice e immediato, ma con le istruzioni talvolta illustrate di questo sito tutto si riduce a un po' di tempo e pazienza. C'è persino la guida per fare il setup di Live Messenger, Live Writer & co. Alla fine ho anche applicato come ultima "taratura" l'elenco di servizi da attivare e disattivare rispetto alle mie esigenze.

Certo che alla fine, nonostante io sia uno dei sostenitori di Windows Vista tutto sommato soddisfatto, rimane il dubbio di come sia possibile che due sistemi praticamente identici (i driver sono esattamente gli stessi di Vista) possano avere prestazioni così differenti...


E con questo facciamo tre post su prodotti. Questa volta però si tratta di un freeware che tengo sempre da parte nel mio cappellino da sistemista. Il post serva da tributo per la completezza e l'affidabilità di questo proxy server freeware made in germany che anche oggi come spesso è accaduto nella mia vista lavorativa si è rivelato di un aiuto strepitoso.

Ricordo ancora nella notte dei tempi quando riuscii a far uscire su internet tutta l'amministrazione dell'azienda presso cui lavoravo solo grazie a questo software. Parlo ormai di 5 anni fa, un tempo enorme in termini informatici. Jana server però è sempre presente e sempre uguale, un po' ostico da capire all'inizio ma poi impareggiabile.

Oggi abbiamo fatto qualche operazione non troppo ortodossa per superare dei problemi alla rete aziendale che naturalmente si propongono sempre e solo quando la data della consegna si profila all'orizzonte. Grazie JANA!

Link: http://www.janaserver.de/


Se per caso vi serve avere un mini web-server, al solo scopo di fare qualche test, c'è un modo semplice di lanciare da codice l'ASP.NET Development Server. Per poterlo fare da un progetto di Visual Studio è sufficiente cercare, via command prompt, il seguente assembly:

c:\WINDOWS\assembly\GAC_32\WebDev.WebHost\8.0.0.0__b03f5f7f11d50a3a\WebDev.WebHost.dll

Dopo averlo referenziato da Visual Studio (è obbligatorio avere Visual Studio perchè questo è un componente che si installa con esso), il seguente codice avvierà un WebServer in local sulla porta 3010:

class Program
{
    
static void Main(string[] args)
    {
        Server server = 
new Server(88, "/imho", "d:\\");
        server.Start();

        Console.ReadLine();
    }
}

Attenzione però che se sviluppate un software usando questa tecnica non potrete mai redistribuirlo per il semplice fatto che l'ASP.NET Development Server è parte di Visual Studio 2005 e la licenza lo impedisce.

Se per caso vi serve un web server opensource, miigliore del vecchio Cassini, alora provate questo che supporta anche completamente ASP.NET.

Link:


Alcuni giorni orsono ho postato un articolo che descriveva le problematiche riguardanti la creazione di un Web Server completamente realizzato in C# con gli strumenti messi a disposizione dal framework .NET. In questa puntata inizieremo ad affrontare i primi due punti esposti in tale articolo per dare loro una soluzione che consenta al nostro Web Server di accettare richieste in ingresso senza per questo impedire che esso possa essere avviato o fermato a piacimento. Come primo passo iniziamo ad analizzare quali sono gli strumenti di cui il framework dispone per metterci in ascolto su una porta tcp/ip pronti ad evadere le richieste dei browser.

Il metodo di gran lunga più semplice per attivare un socket in ascolto su una porta è quello di fare uso della classe TcpListener. Tale classe, ha la capacità di ricevere in ingresso un "EndPoint" (accoppiata IP-porta) e di operare in due modi, dopo che sia stato avviato il binding con il metodo Start(). Il primo metodo richiede che vengano chiamati AcceptSocket() o AcceptTcpClient() provocando il blocco del thread corrente finchè non arrivi una richiesta che ci verrà restituita sotto forma di Socket nel primo caso o di TcpClient nel secondo. Questa modalità "bloccante" non è adeguata a quello che dobbiamo realizzare. Infatti ci troveremmo nella condizione per cui non saremmo in grado di uscire dal thread principale dell'applicazione finchè non giunga una chiamata che sblocchi il metodo. Per fortuna la classe TcpListener dispone di un metodo Pending() che ci informa della presenza di richieste in attesa di essere evase, che poi dovranno essere accettate con i metodi suddetti. Questa modalità di lavoro richiede quindi che si verifichi lo stato di Pending() ad intervalli regolari e solo nel momento in cui esso restituisca true chiamare il metodo più adeguato alle nostre esigenze, che nel nostro caso sarà AcceptTcpClient().

Comincia quindi a prendere forma quello che dovrà essere il corpo principale del nostro main thread. Rimane solo da definire in che modo comuicare a questo ciclo potenzialente infinito che è giunto il momento di uscire. A questo scopo useremo uno degli strumenti che il sistema operativo stesso espone, in particolare un AutoResetEvent, cioè in breve un flag che solleveremo nel momento in cui desideriamo interrompere il servizio http. Su tale evento è possibile usare la funzione di sincronizzazione WaitHandle.WaitAny che verifica lo stato dell'evento per il periodo specificato ed esce indicando il motivo dell'interruzione. Ecco riportato uno spezzone di codice:

/// 
/// Initializes a new instance of the  
class.
/// 

/// The ip address.

/// 
The listen port.

public HttpServer(IPAddress ipAddress, int 
listenPort)
{
    
this
.Address = ipAddress;
    
this
.Port = listenPort;

    
this.StopEvent = new AutoResetEvent(false
);
    
this.Listener = new TcpListener(ipAddress, this
.Port);
}

/// 
/// 
Starts this instance.
/// 

public virtual void Start()
{
    ThreadStart start = 
new 
ThreadStart(ListenThread);
    Thread listenThread = 
new 
Thread(start);
    listenThread.Start();
}

/// 
/// 
Stops this instance.
/// 

public virtual void Stop()
{
    
this
.StopEvent.Set();


/// 
/// 
Listens the thread.
/// 

protected virtual void ListenThread()
{
    
this
.Listener.Start();

    WaitHandle[] waitHandles = 
new WaitHandle[] { this
.StopEvent };

    
while 
(
        WaitHandle.WaitAny(
            waitHandles, 
            100, 
            
false
) == WaitHandle.WaitTimeout)
        
if 
(Listener.Pending())
            EnqueueRequest(
this
.Listener.AcceptTcpClient());

    
this
.Listener.Stop();
}

Questo codice riporta la parte di inizializzazione, i metodi per l'avvio e l'interruzione del web server e ovviamente il main loop. Nel costruttore, uno dei molti che coprono buona parte delle possibili combinazioni di parametri, vengono semplicemente assegnati i valori delle proprietà e creati l'evento e il TcpListener. I metodi Start() e Stop() comandano il thread che esegue il main loop il primo avviandolo e il secondo sollevando l'evento AutoResetEvent che come vedremo fra poco obbliga il main loop ad uscire. Infine il main loop utilizza il metodo statico WaitAny dell'oggetto WaitHandle. Tale metodo è in grado di attendere che un oggetto di un array di WaitHandle cambi di stato e in questo caso esce ritornando l'indice del'oggetto nell'array. Inoltre consente di specificare un timeout oltre il quale ritorna il controllo al chiamante con un valore WaitHandle.WaitTimeout. Ecco quindi che il mainloop non fa altro che dedicare 100 millisecondi all'attesa dell'evento di uscita e ad ogni ciclo verifica lo stato di Pending() che non essendo un WaitHandle non è controllabile da WaitAny. Qualora Pending() sia settato a true il codice si occupa di gestire la richiesta intervenuta.

Il metodo che implementa il mainloop tutto sommato è molto semplice ma è evidente che deve funzionare con puntualità e velocita proprio per evitare che il client riceva delle risposte errate o dei timeout. La scelta del valore di 100 millisecondi è arbitraria. A me è parso un valore ideale abbastanza alto per non avere impatto sulle prestazioni delle macchina dato che comunque in tale periodo il thread appare a tutti gli effetti sospeso come se avesse invocato la Thread.Sleep(), e quindi rilascia le risorse ad altri processi ma anche abbastanza basso perchè un client non debba attendere troppo l'evasione della sua richiesta.

Nela prossima puntata affronteremo finalmente proprio questo punto. A partire dal metodo EnqueueRequest()  parte il codice che accoda la richiesta in arrivo e in seguito la gestisce. Per questo compto la mia scelta è stat quella di preferire l'uso di eventi sulla creazione esplicita di nuovi thread. Ma come ho già detto lo vedremo alla prossima.

powered by IMHO 1.3


Il lavoro di questi giorni sul mio IMHO 2.0 sta vertendo su un tema che ha suscitato il mio interesse e mi ha stimolato molto. La necessità deriva dal nuovo "preview pane" che dovrebbe consentire la visualizzazione dei post già all'interno della finestra di gestione invece che in quella di edit. L'architettura di IMHO, che ricordo essere basata su .NET remoting, per effettuare una preview del post con tutte le immagini ad esso collegate richiederebbe di scaricare in locale il testo del post e tutte le immagini ricreando una copia temporanea da passare al controllo WebBrowser. Pur essendo indubbiamente fattibile questo comporta di dover fare il parsing dell'html e di re-referenziare le immagini, oltre a dover attendere il completo scaricamento dei file prima di iniziare la visualizzazione. L'idea che alla fine mi è balenata è quella di sfruttare al 100% le capacità del controllo WebBrowser e di lasciare a lui l'onere di fare quelo che in effetti è il suo lavoro. Questo però mi ha posto il problema di dover realizzare un mini Web Server che rispondesse alle chiamate HTTP dal lato server del sistema, così da intervenire nel processo il minimo indispensabile. Ecco quindi che comincia con questa puntata una serie di articoli che ripercorrono le tematiche, anche piuttosto complesse che si sono presentate nell'implementare questo affascinante protocollo.

Cominciamo subito con il dire che nel Framework 2.0 esiste una classe, la HttpListener, che in realtà fa già tutto quello che serve. Tale classe però ha una piccola ma significativa limitazione ovvero funziona solo con Windows 2003 Server o con Windows XP dalla SP2 in su. Tale limitazione, che per i più può apparire insignificante, nel mio caso è una barriera insormontabile, infatti è davvero inaccettabile che IMHO non possa funzionare con Windows 2000 che è un sistema ancora molto diffuso o anche solo con Windows XP SP1 o Windows 98. Ecco quindi che ho dovuto rimboccarmi le maniche e iniziare a scrivere il codice di un web server praticamente da zero, anche se lo confesso, pensare di scrivere qualcosa da zero con il framework .NET è proprio impossibile.

Un piccola overview

Pensare di scrivere un web server e farlo sul serio sono due cose molto distanti l'una dall'altra, separate perlomeno dal proverbiale mare. Le problematiche che si debbono affrontare sono le più disparate, e in questo paragrafo vorrei dare un'idea della loro natura.

Il primissimo problema che si incontra è di threading. Un server http, in quanto server non può certo essere un eseguibile in puro stile Java che occupa il desktop del pc quando lanciato. Esso deve essere in grado di funzionare in qualunque momento anche se il server è chiuso in una sala macchine sotto chiave con la macchina non loggata. Ecco quindi che è richiesto che tale server giri sul sistema come servizio windows, e dato che nel mio caso il servizio esisteva già deve anche configurarsi come un thread parallelo eseguito all'interno di tale servizio. In realtà, volendo realizzare una classe furba, si dovrà pensare che ad ogni istanza di classe vi sia un server in ascolto su un determinato indirizzo ip e su una determinata porta. Perciò lanciando più classi si avranno più server contemporaneamente attivi e ad ognuno di essi corrisponderà un Thread che si occupa dell'evasione delle richieste.

Il secondo problema è di comunicazione. Un server http per definizione deve mettersi in ascolto su una determinata porta tcp accogliere richieste ed evaderle. Quindi occorre almeno scomodare i socket per implementare questa fondamentale funzione, considerando però che le richieste pervenute potranno essere multiple che quindi bisognerà lavorare in modo non bloccante. Per fortuna il framework .NET dispone di un set di classi splendide che permettono di assolvere a questa parte in modo molto efficace, anche se comunque del lavoro da fare c'è sempre.

Un altro problema è dato da una affermazione del paragrafo precedente. Un server http deve essere in grado di evadere più richieste contemporaneamente e questo comporta che le richieste debbano essere evase contemporaneamente. Ecco quindi che occorrerà lanciare un thread per ognuna di esse in modo che il thread principale sia libero di tornare in ascolto il più rapidamente possibile.

Bisogna poi considerare che il thread principale non è "infinito" ma anzi deve essere in grado di avviarsi e fermarsi "gracefully" per usare un termine inglese. Questo che può sembrare ovvio, in realtà impedisce di usare appieno alcune classi del framework che nella pratica invece bloccano l'esecuzione fino all'arrivo di una nuova chiamata. Per questo motivo occorrerà definire un AutoResetEvent che informi il thread principale di quando è venuto il momento di uscire.

Infine, last but not least il problema di gran lunga più complesso è quello di fare un parsing efficace delle richieste in arrivo e di creare una struttura che sopperisca per la gran parte ai dettami del protocollo HTTP 1.1. Questo comprende il supporto a tutti i codici nelle risposte, 200, 300, 400 e 500, la lettura degli headers, il supporto ad un subset efficace dei metodi (GET, POST), senza poi considerare che volendo scrivere una singola classe che si occupi di questo bisognerà corredarla dei metodi e delle proprietà adatte a configurarne il funzionamento e a rispondere alle richieste.

Progettiamo le classi

Come ogni buon progetto, la prima fase del nostro lavoro è quella di fare un'ipotesi sulle classi che dovranno essere realizzate. In realtà nel nostro caso il disegno delle classi è addirittura fondamentale trattandosi di un componente che dovrà essere riutilizzato, e quindi a tutti gli effetti di una libreria. L'idea, come dicevo poche righe fa, è quello di avere una classe che una volta istanziata si occupi di tutto ciò che serve. E vero che si potrebbero delegare i vari compiti a varie classi, ma in prima battuta una classe unica mi è sembrata la soluzione migliore. Magari alla fine con un po di refactoring vedremo di definire al meglio il design. Chiamiamo HttpServer tale classe e definiamo che essa avrà un certo numero di costruttori con vari parametri il cui scopo è sostanzialmente di determinare quale indirizzo IP e quale porta essa dovrà usare. La medesima classe inoltre disporrà di un metodo Start() e di un metodo Stop() dei quali non è necessario spiegare l'utilità, ma che in definitiva governeranno l'avvio e l'uscita del thread principale. Infine la classe HttpServer dovrà esporre un evento RequestArrived che consenta all'applicazione che l'ha istanziata di gestire le chiamate e di fornire le corrette risposte. Infatti, a differenza di un normale Web Server, la nostra classe non avrà coscienza (se mi perdonate il termine) della directory da cui prelevare i file, ma semplicemente notificherà per mezzo di un evento l'arrivo della richiesta e demanderà all'handler la creazione della risposta. In questo modo, si potrà agire anche in modi diversi, ad esempio creando al volo le risposte.

Chiaramente, nominando Richiesta e Risposta viene naturale pensare che debbano esistere delle classi che le rappresentano. In particolare esse saranno HttpServerRequest e HttpServerResponse. Mentre la prima verrà creata dal server come risultato del parse della richiesta HTTP, la seconda dovrà essere confezionata dall'handler che gestisce la richiesta sulla base della HttpServerRequest ricevuta.

Infine, almeno per ora occorre considerare che esistono 4 possibili soluzioni di una chiamata HTTP. Queste quattro soluzioni, rispondono alle classi di codice restituito dal web server. 200, sono i codici che informano sul buon esito della richiesta, 300 indicano le richieste di redirect, 400 gli errori di tipo client (ad esempio il famoso 404 not found) e infine gli errori di tipo server che ricadono nella classe 500. Se consideriamo che solo i codici 200 indicano che la richiesta è stata soddisfatta, potremmo considerare gli altri casi come delle eccezioni e trattarli appunto come tali definendo delle opportune classi derivanti da HttpServerException. Quindi per i codici 300 avremo HttpServerRedirectException, per i codici 400 HttpServerClientException, e naturalmente HttpServerServerException per i 500. Mentre codici di tipo 500 potranno essere generati anche dalla classe HttpServer stessa, in caso di una eccezione non gestita interna (internal server error vi dice niente?), tutti gli altri dovranno essere sollevati dall'handler che gestirà le richieste. Internamente il server http elaborerà queste eccezioni trasformandole nel relativo codice di ritorno.

Ecco quindi che abbiamo definito le classi del dominio, che nelle prossime puntate appunto cominceremo a realizzare. Per questa volta l'articolo è finito, ma naturalmente vi invito a mandarmi i vostri commenti in merito al fine di migliorare il design prima di procedere con le successive fasi.


Lavorando su IMHO 2.0 mi sono trovato a dover scrivere un piccolo web server per visualizzare i post nel preview pane. Così, dato il notevole l'interesse del lavoro ho deciso di scrivere qualche articolo per spiegare nel dettaglio come sono arrivato ad una buona soluzione usando gli strumenti del framework 2.0. E' utile precisare che in questo esempio non è utilizzata la classe HttpListener perchè essa non è supportata da tutti i sistemi operativi Microsoft.

Buona lettura: http://blog.boschin.it/articles/webserver1.aspx

keywords: http protocol webserver

powered by IMHO 1.3


Della mia pessima esperienza con il Community Server 1.0 oramai ne siete a conoscenza, ma stamane mi sono scontrato nuovamente con il preteso erede del glorioso .TEXT. Mi ha scritto una persona chiedendomi come mai l'adapter per Community Server incluso in IMHO 1.2/1.3 non funzionasse. Non ci è voluto molto a capire il motivo del malfunzionamento. Il mio adapter è stato scritto su CS 1.0 mentre il mio interlocutore stava tentando di postare su un CS 1.1

Ho indagato più a fondo e alla fine ho scoperto la differenza. Praticamente il ticket di autenticazione che viene inviato al CS, composto da Username, Password e BlogId ha visto repentinamente cambiare il nome di quest'ultima proprietà da BlogName a ServiceName. Sono un fan sfegatato del refactoring, e soffro molto, quasi fisicamente quando nel mio codice c'è anche solo una variabile con un nome sbagliato. Però questo è troppo. in casi come questo la compatibilità all'indietro deve essere mantenuta a tutti i costi e non c'è nessuna scusa per fare un cambiamento del genere senza almeno prevedere di accettare entrambi i nomi.

Alla fine ho dovuto produrre un altro Adapter, a supporto di questa nuova versione, sperano che l'uscita della 1.2 non mi costringa nuovamente a rivedere il codice. Al più presto sarà online.

powered by IMHO 1.3


Grazie al prezioso aiuto di Mauro Sagratella, ora vi posso comunicare che l'ultima versione di IMHO risolve anche i problemi di ISA Server. Mauro mi ha supportato testando IMHO su ISA Server di cui io non dispongo e ha fatto anche qualche prova di codice che mi ha aiutato ad arrivare ad una felice conclusione. In questo post quindi vale la pena di discutere i due aspetti della questione:

1) Come configurare IMHO per uscire su ISA Server

E' molto semplice, se il vostro browser Internet Explorer naviga correttamente non avete che da impostare l'opzione "Use proxy from Internet Explorer" e tutto funzionerà correttamente.

2) Come faccio ad uscire su ISA Server con un mio programma

Anche qui la questione si risolve semplicemente. Ecco le due righe di codice che sono la chiave di tutto:

...

WebProxy defaultProxy = 
    WebProxy.GetDefaultProxy();

defaultProxy.Credentials = 
    CredentialCache.DefaultCredentials;

...

In sostanza occorre dare le credenziali dell'utente correntemente loggato al sistema al proxy che poi verrà usato per uscire su internet.

[now playing: Woodstock 99 Full Set (01:52:48) - Metallica]

powered by IMHO 1.3