|
|
venerdì 26 aprile 2013
Nuova release per Microsoft Enterprise Library. Tutti i dettagli del caso qui.
mercoledì 24 aprile 2013
Alla fine, sono riuscito a pubblicare le mie prime 4 applicazioni nello Store di Windows 8. L’obiettivo è raddopiare il numero entro la fine di maggio. Se avete voglia di provarle (sono tutte free) e indicarmi qualche suggerimento per le versioni future ed attuali, di seguito link e nomi : Lazio: Cultura e Turismo L'applicazione "Lazio: Cultura e Turismo", è un elenco dei Punti d'Interesse (POI) Culturali del Lazio: Musei, Statue, Monasteri, Dipinti, Abbazie, Castelli, Torri ecc....Per ogni POI è presente una descrizione in Italiano (eventualmente in Inglese), foto e geolocalizzazione. Il catalogo dati è mantenuto e fornito da "Lazio futouring", sito internet: http://www.futouring.eu. Farmacie Italiane Elenco completo delle farmacie italiane aperte al pubblico, comprensivo di dati di localizzazione e geoloclalizzazione. I dati sono mantenuti e forniti tramite piattaforma"cloud" del "Ministero della Salute". Istituti Scolastici Provincia di Roma "Istituti Scolastici Provincia di Roma" Catalogo con geolocalizzazione degli istituti scolastici (superiori) della provincia di Roma. I dati base sono forniti dalla piattaforma "Open Data". Roma ProvinciaWiFi Individua facilmente apparati WiFi della provincia di Roma per l'accesso gratuito ad Internet. I dati di geolocalizzazione sono ottenuti tramite il "Portale Opendata della Provincia di Roma". Buon divertimento :-D.
venerdì 22 marzo 2013
Se domani non avete proprio nulla da fare :-) possiamo vederci a Codemotion 2013 Roma.  Una sessione introduttiva all’utilizzo del Framework ASP.NET Web Api per lo sviluppo di applicazioni RESTful.
sabato 9 marzo 2013
Con il rilascio dell’aggiornamento ASP.NET 2012.2 di qualche settimana fa, lo sviluppo di una “Help Page” per Web Api, utilizzando l’apposito Package di NuGet, é un’attività che impegna meno di 5 minuti (per completezza di informazione, era già presente una versione alpha del Package prima del rilascio ufficiale).
1) Dalle “references” del progetto Web da “documentare”, apriamo la finestra per la gestione dei “Packages” di NuGet:
2) Cerchiamo la voce “Web Api Help Page” e clicchiamo su “Install” (verranno installate le dipendenze necessarie):
3) Al progetto verrà aggiunta l’area “HelpPage” sotto la cartella “Areas”, con tutte le classi necessarie (css compreso):
4) La classe XmlDocumentationProvider che implementa l’interfaccia IDocumentationProvider permette di documentare le nostre API nel caso più semplice utilizzando i commenti che decorano le Web API direttamente nel codice (implementando l’interfaccia IDocumentationProvider é possibile personalizzare questo comportamento).
5) Aggiungiamo nel Global.asax.cs la riga di codice seguente:
config.Services.Replace(typeof(IDocumentationProvider), new XmlDocumentationProvider(HttpContext.Current.Server.MapPath("~/App_Data/file.xml")));
6) A questo punto non ci resta che eseguire la nostra applicazione e digitare “Help” nella barra degli indirizzi:
A questo punto é sufficiente passare alle personalizzazioni del caso :-).
mercoledì 20 febbraio 2013
Rilasciata la versione finale di “ASP.NET and Web Tools 2012.2 Update”, un download che arrichisce, non di poco, le funzionalità esistenti, in Visual Studio 2012 e ASP.NET (tra le novità, OData EndPoint in ASP.NET Web API, ASP.NET SignalR, Single Page Applications). Tutti i dettagli del caso sul post originale sul blog di Scott Guthrie.
lunedì 28 gennaio 2013
Ultimamente mi trovo a lavorare su di un progetto che utilizza WCF e MSMQ. Una delle classiche operazioni quando si lavora con queste tecnologie è sicuramente recuperare il numero di messaggi presenti in una coda. Tra documentazione e ricerche su internet, alla fine si “scopre” che ci sono diversi metodi per risolvere lo stesso problema: - Cursori di MSMQ
- Utilizzo di GetAllMessages
- Utilizzo di GetEnumerator2
- PowerShell
- Performance Counter
Traducendo il tutto in righe di codice, per il punto 1) abbiamo: public int CountByCursor()
{
int count = 0;
Cursor cursor = _messageQueue.CreateCursor();
Message m = CursorPeekWithoutTimeout(cursor, PeekAction.Current);
if (m != null)
{
count = 1;
while ((m = CursorPeekWithoutTimeout(cursor, PeekAction.Next)) != null)
{
count++;
}
if (m != null) m.Dispose();
}
cursor.Dispose();
return count;
}
private Message CursorPeekWithoutTimeout(Cursor cursor, PeekAction action)
{
Message ret = null;
try
{
ret = _messageQueue.Peek(new TimeSpan(1), cursor, action);
}
catch (MessageQueueException mqe)
{
if (mqe.MessageQueueErrorCode != MessageQueueErrorCode.IOTimeout)
{
throw;
}
}
return ret;
}
Sinceramente questo è il metodo che più non mi piace, sarà per la parola “Cursore”, sarà per la gestione dell’eccezione, sarà perchè la vedo poco pulita.
Passiamo al punto 2):
public int CountByGetAllMessages()
{
return _messageQueue.GetAllMessages().Length;
}
Semplice e pulita, ma come vedremo a breve, le prestazioni scendono con l’aumentare dei messaggi in coda.
Punto 3), “GetMessageEnumerator2”:
var x = _messageQueue.GetMessageEnumerator2();
int counter = 0;
while (x.MoveNext())
{
counter++;
}
return counter;
Sfruttiamo il MessageEnumerator ritornato dal metodo GetEnumerator2 ed iteriamo per spostare il cursore fino alla fine della coda.
Punto 4), “PowerShell” (in questo caso mi sono limitato a copiare del codice trovato in rete):
var path = string.Format(@"\\{0}\root\CIMv2", machine);
ManagementScope scope;
if (string.IsNullOrEmpty(username))
{
scope = new ManagementScope(path);
}
else
{
var options = new ConnectionOptions { Username = username, Password = password };
scope = new ManagementScope(path, options);
}
scope.Connect();
if (queuePath.StartsWith(".\\")) queuePath = queuePath.Replace(".\\", string.Format("{0}\\", machine));
string queryString = String.Format("SELECT * FROM Win32_PerfFormattedData_msmq_MSMQQueue");
var query = new ObjectQuery(queryString);
var searcher = new ManagementObjectSearcher(scope, query);
IEnumerable<int> messageCountEnumerable =
from ManagementObject queue in searcher.Get()
select (int)(UInt64)queue.GetPropertyValue("MessagesInQueue");
var x = messageCountEnumerable.First();
return x;
ed infine il punto 5) “Performance Counter”:
System.Diagnostics.PerformanceCounter backupQueueCounter = new System.Diagnostics.PerformanceCounter(
"MSMQ Queue", "Messages in Queue", "queue_path");
return backupQueueCounter.NextValue();
Bene, ora quale usare ? Proviamo con un piccolo test: ad una coda privata aggiungiamo 10.000 messaggi per volta (all’interno di un ciclo) e proviamo ad utilizzare i metodi su descritti per recuperare il numero di messaggi presenti in coda (si suppone che tra un conteggio e l’altro nella coda non vengano aggiunti altri messaggi). Iteriamo il procedimento per tre volte.
Di seguito i risultati ottenuti (espressi in millisecondi, per le misure del tempo di esecuzione è stata utilizzata la classe System.Diagnostics.Stopwatcher):
Prima Iterazione
| #Msgs |
MSMQ Cursor |
GetAllMessages |
GetEnumerator2 |
PowerShell |
Performance C. |
| 10.000 |
449,816 |
580,703 |
36,37 |
78,543 |
351,86 |
| 20.000 |
928,18 |
1.297,72 |
78,16 |
9,888 |
0,462 |
| 30.000 |
1.340,44 |
1.854,52 |
137,82 |
10,563 |
1,121 |
| 40.000 |
1.769,73 |
2.656,28 |
194,652 |
12,061 |
3,187 |
| 50.000 |
2.188,74 |
3.427,84 |
190,672 |
10,739 |
0,452 |
| 60.000 |
2.631,29 |
3.909,71 |
231,995 |
10,219 |
0,364 |
| 70.000 |
3.006,52 |
4.771,09 |
264,112 |
5.802,42 |
0,462 |
| 80.000 |
3.469,49 |
6.116,47 |
309,691 |
10,075 |
0,545 |
| 90.000 |
4.000,00 |
6.134,66 |
372,885 |
9,876 |
0,435 |
| 100.000 |
4.544,33 |
6.932,08 |
424,196 |
9,024 |
0,41 |
Seconda Iterazione
| #Msgs |
MSMQ Cursor |
GetAllMessages |
GetEnumerator2 |
PowerShell |
Performance C. |
| 10.000 |
475,357 |
609,866 |
38,022 |
285,978 |
351,955 |
| 20.000 |
912,591 |
1.315,49 |
76,912 |
10,453 |
0,502 |
| 30.000 |
1.417,26 |
2.066,92 |
122,745 |
11,156 |
0,366 |
| 40.000 |
1.901,66 |
2.718,64 |
153,373 |
9,947 |
0,349 |
| 50.000 |
2.393,97 |
3.386,43 |
203,553 |
10,962 |
0,358 |
| 60.000 |
2.659,28 |
4.546,84 |
280,257 |
9,832 |
0,413 |
| 70.000 |
3.246,77 |
4.938,01 |
278,404 |
11,664 |
0,517 |
| 80.000 |
3.718,89 |
5.881,67 |
330,857 |
13,688 |
0,506 |
| 90.000 |
4.230,99 |
6.677,00 |
362,374 |
10,155 |
0,508 |
| 100.000 |
4.832,89 |
7.585,19 |
464,216 |
16,495 |
0,681 |
Terza Iterazione
| #Msgs |
MSMQ Cursor |
GetAllMessages |
GetEnumerator2 |
PowerShell |
Performance C. |
| 10.000 |
533,294 |
621,392 |
41,496 |
79,286 |
376,431 |
| 20.000 |
911,513 |
1.338,41 |
79,827 |
9,354 |
0,38 |
| 30.000 |
1.339,34 |
2.123,46 |
120,693 |
12,969 |
0,414 |
| 40.000 |
1.799,28 |
2.658,01 |
158,606 |
9,423 |
0,374 |
| 50.000 |
2.196,96 |
3.221,87 |
199,273 |
10,413 |
0,426 |
| 60.000 |
2.562,49 |
4.140,15 |
257,22 |
8,81 |
0,411 |
| 70.000 |
3.358,83 |
4.715,56 |
327,474 |
14,808 |
0,53 |
| 80.000 |
4.417,58 |
6.690,44 |
316,044 |
17,334 |
0,825 |
| 90.000 |
4.185,52 |
6.229,67 |
340,457 |
11,773 |
0,396 |
| 100.000 |
4.407,13 |
6.658,46 |
390,498 |
12,944 |
0,589 |
Dai risultati ottenuti si ottiene che l’utilizzo del “Performance Counter”, in caso di letture successive, sembrerebbe essere quello più efficiente.
In attesa di altri giudizi ed approfondimenti :-).
mercoledì 12 dicembre 2012
Nuova alpha release della versione 6 di Entity Framework, disponibile tramite NuGet. Al solito, tutti i dettagli direttamente sul post del blog di ADO.NET.
martedì 27 novembre 2012
E’ stato rilasciato “l'’Update 1” di Visual Studio 2012. Download qui (multi-language), maggiori dettagli, qui. Per una versione “offline”, è possibile eseguire i passaggi descritti in questo post.
mercoledì 7 novembre 2012
Per chi se lo fosse perso :-) : EF6 Alpha 1. Tra le novità più interessanti il supporto Async per “Query and Save”.
venerdì 21 settembre 2012
Post promemoria: interessante ed abbondante elenco di Micro-Framework (completo di “motore di ricerca”) microjs.com
lunedì 10 settembre 2012
Nella prima parte dell’articolo abbiamo introdotto i WebSocket sviluppando una semplice applicazione composta da un client che invia dei messaggi di testo ad un server (WebSocket Server), il quale risponde inviando un testo ed un numero che rappresenta la lunghezza del messaggio ricevuto. Nel post precedente abbiamo descritto con maggior dettaglio il codice lato client demandando a questa seconda parte maggiori approfondimenti relativamente alla parte server il cui codice è composto dalla semplice classe WebSochetHandler.ashx, la quale implementa l’interfaccia IHttpHandler, ragion per cui è necessario scrivere del codice per il metodo ProcessRequest(HttpContext context), per l’elaborazione delle richieste Web HTTP, e la proprietà IsReusable che restituisce un valore che indica se sia possibile riciclare la stessa istanza di classe che implementa IHttpHandler per una successiva richiesta. Per quanto concerne IsReusable, non dovendo memorizzare nulla tra una richiesta e l’altra, il codice è semplicemente: public bool IsReusable
{
get
{
return true;
}
}
Mentre, per il metodo ProcessRequest(…) abbiamo :
public void ProcessRequest(HttpContext context)
{
if (context.IsWebSocketRequest)
{
context.AcceptWebSocketRequest(WebSocketRequestHandler);
}
else
{
context.Response.StatusCode = 400;
}
}
Utilizzando la proprietà IsWebSocketRequest verifichiamo che la richiesta entrante sia una richiesta WebSocket valida, in caso positivo demandiamo la gestione della richiesta al metodo WebSocketRequestHandler così definito:
public async Task WebSocketRequestHandler(WebSocketContext webSocketContext)
{
byte[] buffer = new byte[MAX_MESSAGE_SIZE];
WebSocket webSocket = webSocketContext.WebSocket;
while (webSocket.State == WebSocketState.Open)
{
WebSocketReceiveResult result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
switch (result.MessageType)
{
case WebSocketMessageType.Close:
await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closed.", CancellationToken.None);
break;
case WebSocketMessageType.Binary:
await webSocket.CloseAsync(WebSocketCloseStatus.InvalidMessageType, "Not supported.", CancellationToken.None);
break;
case WebSocketMessageType.Text:
int count = result.Count;
while (result.EndOfMessage == false)
{
if (count >= MAX_MESSAGE_SIZE)
{
string closeMessage = string.Format("Maximum message size: {0} bytes.", MAX_MESSAGE_SIZE);
await webSocket.CloseAsync(WebSocketCloseStatus.MessageTooBig, closeMessage, CancellationToken.None);
return;
}
result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer, count, buffer.Length), CancellationToken.None);
count += result.Count;
}
string receivedMessage = Encoding.UTF8.GetString(buffer, 0, count);
string outputMessage = "Text Length: " + receivedMessage.Length;
await webSocket.SendAsync(new ArraySegment<byte>(Encoding.UTF8.GetBytes(outputMessage)), WebSocketMessageType.Text, true, CancellationToken.None);
break;
}
}
}
In dettaglio, quando invochiamo il metodo WebSocketRequestHandler, ASP.NET passa un’istanza della classe WebSocketContext contenente informazioni quali l’URI utilizzato per stabilire la connessione (compresi i parametri della Query String) e la collezione dei cookies inviati. Per accedere ai metodi per la ricezione e l’invio dei dati è necessario accedere alla proprietà WebSocket . A questo punto, utilizziamo la proprietà State per verificare lo stato della connessione, rimanendo “in ciclo” finché la connessione rimane aperta. Per ricevere i dati utilizziamo il metodo ReceiveAsync che accetta due parametri: un ArraySegment in cui scrivere i dati ricevuti (buffer) ed un Cancellation Token, nel nostro caso CancellationToken.None. Il metodo ritorna un’istanza di WebSocketReceiveResult che rappresenta il risultato di una singola operazione ReceiveAsync. Tramite la proprietà MessageType della classe risultato verifichiamo il tipo di messaggio:
- Close: è stato inviato un close frame (vedi prima parte). A questo punto il server partecipa all’handshake di chiusura utilizzando il metodo CloseAsync. Trattandosi di una normale chiusura, ci limitiamo ad utilizzare la voce Normal dell’enumerativo WebSocketCloseStatus.
- Binary: non supportato dalla nostra applicazione, pertanto iniziamo il processo di chiusura della connessione e specifichiamo al client che il tipo dati inviato non è supportato (utilizziamo l’apposito valore dell’enumerativo).
- Text: tramite la proprietà EndOfMessage, entriamo in un loop finché non abbiamo letto il contenuto dell’intero del messaggio (o non si raggiunge la dimensione massima del messaggio). Una volta ricevuto il messaggio, utilizzando l’encoding opportuno (UTF8, per formati diversi è necessario utilizzare il formato binario) “leggiamo” la stringa ed inviamo un testo con l’indicazione della lunghezza della stringa ricevuta tramite il metodo SensAsync.
Il terzo ed ultimo post della serie dedicato alla “costruzione della lavagna” condivisa tra client Web/Windows utilizzando i WebSocket e l’oggetto HTML canvas.
venerdì 7 settembre 2012
Chi sviluppa per il Web, si scontra ogni giorno con le “limitazioni” del modello request-response di HTTP, il quale non è pensato “ad hoc” per applicazioni real time, o comunicazione bidirezionale client-server. Per questi scenari, spesso vengono utilizzate tecniche di polling, da parte del client, per verificare l’eventuale presenza di dati “freschi”, eseguendo continuamente delle richieste HTTP, comportando dei “costi”: il server deve utilizzare differenti connessioni TCP per ogni client (una per inviare informazioni ed una per rispondere alla richiesta di aggiornamenti), un continuo scambio di messaggi client-server (comportando quindi un aumento del traffico di rete). Potrebbe sembrare cosa da poco, ma se pensiamo ad applicazioni web con migliaia di client connessi, le risorse di server e banda potrebbero essere velocemente consumate (e dato che la nostra epoca è affamata di risorse potremmo trovarci in situazioni poco piacevoli). Quindi, quale potrebbe essere la soluzione ? utilizzare una singola connessione TCP per gestire il traffico in entrambe le direzioni, ovvero il protocollo WebSocket, che se gestito mediante le WebSocket API (WSAPI), fornisce un’ottima alternativa alla tecnica di polling di cui parlavamo in precedenza. Possiamo utilizzare i WebSocket in diversi scenari: giochi, applicazioni di editing real time multi-utente, UI web che espongono dati lato server in tempo reale ecc .… tutto questo condividendo le porte standard HTTP 80 e 443, “attraversando” firewalls, proxies e router senza problemi. Possiamo riassumere le due “tecniche” discusse in precedenza con la figura seguente;  dalla quale si evince come l’utilizzo del “polling” comporti una maggiore latenza nella trasmissione delle informazioni utili. Nell’immagine, nella comunicazione bidirezionale offerta dai WebSocket, come primo passo (dal client verso il server) c’è la voce “WebSocket upgrade”, cosa sarà mai ?, un passo per volta. Il protocollo è diviso in due parti: handshakes e transfer data. Durante la prima parte (di negoziazione), client e server comunicano scambiandosi dei pacchetti di controllo per stabilire una connessione WebSocket. Il client invia una richiesta di questo tipo:
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Version: 13
ed il server (normalmente) dovrebbe rispondere con:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
In dettaglio, il processo di connessione parte con una standard GET HTTP, e fin qui tutto regolare:
GET /echo HTTP/1.1
Host: example.microsoft.com
poi, l’header “Upgrade” richiede al server di cambiare il protocollo a livello di application-layer da HTTP a WebSocket:
Upgrade: websocket
Connection: Upgrade
Il valore presente in Sec-WebSocket-Key inviato dal client verrà utilizzato dal server per far capire al chiamante che “comprende” la richiesta:
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
L’header Sec-WebSocket-Version identifica la versione del protocollo da utilizzare:
Sec-WebSocket-Version: 13
A questo punto, se il server “comprende” la nostra richiesta , il server eseguirà un “Upgrade” dell’application-layer e risponderà con lo stato HTTP 101. Il valore contenuto in Sec-WebSocket-Accept verrà utilizzato dal client per validare che il server è un WebSocket server e non un “semplice” HTTP server.
Una volta che client e server hanno entrambi inviati i loro handshakes, (e l’handshaking ha avuto successo) può iniziare il trasferimento dati su un unico canale di comunicazione bidirezionale, tra client e server, sfruttando la connessione TCP precedentemente stabilita.
I dati trasferiti tra le due parti sono racchiusi in unità logiche chiamate “messaggi”, ogni messaggio è fisicamente composto da uno o più frames.
Dopo la teoria la pratica…
Il protocollo WebSocket, definisce due nuove tipologie di URI:
- ws://host [: port] path [? query] (di default usa la porta 80 e connessione non cifrata)
- wss://host [:port] path [? query] (di default utilizza la porta 443, ed una connessione cifrata HTTP over TLS)
Le ultime specifiche del protocollo sono definite nel documento RFC 6455. Per “sporcarci le mani” con i WebSocket, possiamo sviluppare un semplice pagina web con estensione .html, come la seguente:

I bottoni Open e Close, sono rispettivamente utilizzati per aprire e chiudere la connessione del WebSocket, mentre il campo text per inviare un messaggio al server, il quale risponderà inviando al client la lunghezza della stringa inviata (ovviamente il livello pratico dell’esempio è praticamente nullo ).
Per stabilire una connessione con il server, utilizziamo le seguenti righe di codice client-script:
var uri = 'ws://localhost:9915/WebSocketHandler.ashx';
websocket = new WebSocket(uri);
Per conoscere quando la connessione con il server è stata creata è necessario sottoscriversi all’evento onopen:
websocket.onopen = function () {
appendData("Connected.");
appendData(uri);
$('#wsform').submit(function (event) {
websocket.send($('#inputbox').val());
$('#inputbox').val('');
event.preventDefault();
});
$("#closeButton").removeAttr("disabled");
};
Con lo script precedente, all’apertura della connessione visualizziamo il messaggio “Connected.” e l’URI utilizzato per la connessione. Dopodiché ci registriamo all’evento submit per inviare al server, utilizzando l’API Send, messaggi al WebSocket server sotto forma di testo UTF-8 o Blobs.
Per ricevere messaggi, dobbiamo registrarsi all’evento onmessagge dell’oggetto websocket il quale riceve messageEvent che espone la proprietà data, contenente le informazioni inviate al client:
websocket.onmessage = function (messageEvent) {
var receivedData = messageEvent.data.toString();
appendData(receivedData);
};
Il codice precedente è veramente banale, in quanto si limita a recuperare il testo inviato dal server in risposta al client e visualizzarlo sul browser tramite un div.
Come per l’apertura, c’è una sorta di handshaking per la chiusura della connessione, che può essere iniziata indipendentemente dal client o dal server. Chi inizia il processo di chiusura, invia uno speciale frame, detto close frame, che può contenere, opzionalmente, un codice di stato (il protocollo fornisce un insieme di codici di stato appropriati per la chiusura) e la ragione (una descrizione testuale) della chiusura. Quando una delle due parti riceve un close frame, invia lo stesso frame all’altra parte (eventualmente, prima di rinviarlo, invia i messaggi pending) e la comunicazione viene chiusa.
Per iniziare il processo di close handshake, bisogna invocare l’API close:
function closeWebSocket() {
websocket.close(1000, "Normal.");
}
Il valore 1000 indica lo stato “Normal Closure”. Come “ragione” della chiusura specifichiamo il testo “Normal”. Per sapere quando la chiusura è stata completata, ci sottoscriviamo all’evento onclose:
websocket.onclose = function () {
appendData("Closed.");
$("#closeButton").attr("disabled", "disabled");
};
Con la funzione precedente, visualizziamo il messaggio “Closed.”, e disabilitiamo il button per la chiusura del WebSocket.
La parte server è composta da una classe IHttpHandler che fa uso della classe WebSocketContext (.NET 4.5) utilizzata per accedere alle informazioni di WebSocket handshake. Attraverso altri semplici post, l’obiettivo è realizzare una semplice “lavagna” interattiva real time, utilizzando sia un browser web, che un client WPF, come mostrato seguente:

A tal fine, utilizzeremo lato Windows, la classe ClientWebSocket, presente nel namespace System.Net.WebSockets, la quale fornisce un client per connettersi a servizi esposti tramite WebSocket.
mercoledì 22 agosto 2012
Quando utilizziamo le Web API, per leggere e scrivere oggetti nel corpo di un messaggio Http utilizziamo delle classi particolari, le media-type formatters. "Gratis" Web API fornisce media-type formatters per JSON e XML, utilizzate secondo della richiesta da parte dei client (“Accept”). Se JSON e XML non sono i "formati" di cui abbiamo bisogno possiamo sempre creare la nostra classe derivata da MediaTypeFormatter o BufferedMediaTypeFormatter, rispettivamente per scenari asincroni o sincroni, ma non sono l’argomento di questo post promemoria. Quando abbiamo a che fare con grafi di oggetti complessi, possono crearsi situazioni in cui abbiamo riferimenti circolari tra oggetti. Ad esempio in uno scenario di questo tipo:  Dove abbiamo due classi, Book ed Author , referenziate tramite collection (praticamente un’associazione molti-a-molti) l’una con l’altra. Se abbiamo una Web API di questo tipo : private BookshelfDb _db = new BookshelfDb();
public IEnumerable<Book> GetBooks()
{
return _db.Books.Include(b => b.Authors).AsEnumerable();
}
...
ed una configurazione standard delle Web API, ad eccezione dell’indentatura:
JsonMediaTypeFormatter json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
json.Indent = true;
In presenza di dati, invocando GetBooks() (ad esempio tramite browser), otterremo un’eccezione di questo tipo:
{
"Message": "An error has occurred.",
"ExceptionMessage": "The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; charset=utf-8'.",
"ExceptionType": "System.InvalidOperationException",
"StackTrace": null,
"InnerException": {
"Message": "An error has occurred.",
"ExceptionMessage": "Self referencing loop detected with type 'BookshelfWebApi.Models.Book'. Path '[0].Authors[0].Books'.",
"ExceptionType": "Newtonsoft.Json.JsonSerializationException",
"StackTrace": " …
}
La soluzione al problema è abbastanza semplice in quanto è sufficiente aggiungere la riga:
json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.All;
Il caso Xml, non è immediato come nel caso JSON, in quanto è necessario decorare le classi con l’attributo DataContract impostando la proprietà IsReference a true. In questo caso però è necessario decorare anche le proprietà con l’attributo DataMember:
[DataContract(IsReference = true)]
public class Book
{
public Book()
{
this.Authors = new List<Author>();
}
[DataMember()]
public int Id { get; set; }
[DataMember()]
public int Paperback { get; set; }
[DataMember()]
public string Title { get; set; }
[DataMember()]
public string ISBN_10 { get; set; }
[DataMember()]
public string ISBN_13 { get; set; }
[DataMember()]
public string Language { get; set; }
[DataMember()]
public string Publisher { get; set; }
[DataMember()]
public ICollection<Author> Authors { get; set; }
}
Se non si vuole “sporcare” le classi “farcendole” di attributi possiamo optare per un DataContractSerializer. Le Web API possono essere configurate modificando il codice presente nella classe WebApiConfig.cs:

Quanto detto è sicuramente famigliare per chi espone entità collegate tramite Http, ad esempio utilizzando WCF.
martedì 21 agosto 2012
Pubblicata l'agenda dell'evento ALM@Work organizzato da DomusDotNet per il 28 settembre 2012 presso la sede Microsoft di Roma, insieme a Matteo Emili e Gian Maria Ricci, MVP italiani di Visual Studio ALM.
Tutti i dettagli dell'agenda ed il link per l'iscrizione qui .
giovedì 16 agosto 2012
Con l’arrivo in RTM di Windows 8 e Visual Studio 2012 è stata rilasciata la nuova versione di Entity Framework (scaricabile ovviamente tramite NuGet). Le novità presenti sono diverse, quella più “gettonata” è sicuramente il supporto agli “Enum”. Diverse novità coinvolgono anche il Designer di EF per Visual Studio 2012, come il supporto a diagrammi multipli per lo stesso modello (una delle funzionalità che più apprezzo). Per tutti i dettagli del caso, per la compatibilità delle funzioni utilizzabili secondo del targeting del .NET Framework, lista dei bug corretti ed altro, è possibile iniziare da qui.
|