WCF, MSMQ e Service Broker
Posted by imperugo in Windows Communication Foundation on Monday 21 July 2008 at 6:00 PM
Ai Community Days, con Stefano durante la sessione "Creare applicazioni web service-based con .NET 3.5" abbiamo parlato di Message Queue, ma subito dopo ci è stato chiesto il perchè andare ad utilizzare Message Queue in alternativa ai Service Broker di SQL Server.
La decisione non è affatto facile in quanto ognuno dei due ha dei punti a favore nei confronti dell'altro.
Per prima cosa c'è da dire che MSMQ è integrato con il sistema operativo fin dai tempi di Windows 95, caratteristica non da poco in quanto non richiede costi di licenza aggiuntiva a differenza dei Service Broker che richiedono una licenza di SQL Server.
Altra caratteristica che gioca a favore di MSMQ è l'integrazione a costo zero con WCF, infatti quest'ultimo ha già un transport channel per MSMQ, cosa non presente per i Service Broker (qui nasce la domanda, perchè?).
Cambiando sponda con Service Broker si ha il vantaggio del repository, che è il database di Sql Server e questo ci permette di evitare transazioni distribuite consentendoci maggiore performance.
Sicuramente per la parte di sviluppo applicativo MSMQ la vince sui Service Broker, in quanto bastano poche righe di codice WCF per poter cominciare subito ad utilizzarlo, e questa non è una caratteristica da poco, ma non si può dire se è meglio uno o l'altro, la scelta va ponderata in base alla propria esigenza.
Ciauz
Community Days Again
È un po di tempo che non mi si sente sul blog, ma sono tornato a scrivere un post per ringraziare Stefano e Daniele per avermi dato la possibilità di tenere una sessione (la mia prima) ai Community Days.
Poter spiegare parte della mia esperienza in MTV mi ha fatto molto piacere, e poi, chi mi conosce, sa quanto sono innamorato di WCF e che starei sempre lì a parlarne :).
Devo dire che è stata un'emozione unica, difficilmente ripetibile, che ancora oggi faccio fatica a realizzare nella mente.
Ovviamente ringrazio tutti i ragazzi dello staff di aspitalia e ugidotnet insieme a tutte le persone presenti alla sessione con cui ho avuto il piacere di parlare e discutere sul materiale trattato.
Infine volevo dedicare questo mio traguardo professionale ad una persona a me molto cara che ora non c'è più ma che resterà per sempre nella mia vita e che sicuramente sarebbe stata fiera di me.
Byez
Un uomo un mito!
Ma tu guarda chi si incontra alla PDC2008 di Los Angeles.
![]()
![]()
Managed Services Engine
Posted by imperugo in Windows Communication Foundation on Wednesday 20 February 2008 at 5:00 PM
Su suggerimento dello Sciuro Sudano ho dato un'occhiata a Managed Services Engine che in ambienti tipo quello descritto in questo post, in cui si ha un alto numero di endpoint può essere una manna dal cielo.
Per chi non lo conoscesse già, MSE (scaricabile da CodePlex), non è altro che un repository di servizi con il compito di fare da routing di tutti i client verso i vari servizi sparsi nella rete.
Si provi ad immaginare di dover cambiare indirizzo ad un servizio referenziato da 40 client? Sarebbe di difficile e di scomoda gestione, almeno 40 cambi configurazione e 40 riavvii dei vari applicativi.
Con MSE vi basta far puntare il vostro client al servizio che a sua volta ridirigerà le chiamate al servizio corretto, così nel caso si decida di cambiare un endopoint, una porta, o quel che volete, vi basta farlo solo su MSE, e non su tutti i client, poi come per incanto i 40 cambi di configurazione si traducono in un'unica operazione!
Beh mica male direi.
A tutto ciò va aggiunto il fatto che questo tool è dotato di un'ottimo wizard che segue l'utente durante la configurazione dei vari endpoint.
Ovviamente gli endpoint supportati da wcf li abbiamo tutti come mostrato dallo screenshot seguente:
![]()
ma si ha la possibilità di definirne dei propri.
Per la memorizzazione delle varie configurazione si appoggia a SQL Server, ma la creazione delle varie tabelle necessarie al suo funzionamento è del tutto automatizzata dal suo setup (cosa non sempre scontata in progetti open source)
Sono rimasto così impressionato dall'efficacia e utilità di questo tool che mi sembrava giusto parlarne.
Una grazie allo Sciuro Sudano per la dritta.
Ciauz
WCF + MSMQ Binding
Posted by imperugo in Windows Communication Foundation on Sunday 03 February 2008 at 5:00 PM
In quest'ultimo periodo, in azienda, stiamo organizzando e progettando delle nuove parti di un'applicativo fortemente basato su servizi.
In questo e in molti altri scenari, si ha la necessità di avere una forte scalabilità e la certezza di non perdere nessun dato anche nel caso uno dei servizi si offline per manutenzione e/o problemi tecnici di qualsiasi tipo.
Dopo varie analisi con lo sciur Sudano aka Janky (spinto dalle teorie di Pat Helland :D, altro che notepad) abbiamo deciso di implementare per i punti crifiti dell'applicativo Microsoft Message Queue con WCF e, devo dar atto che le suo potenzialità e casi di utilizzo sono veramente impressionati.
Basti pensare che in tutte quelle situazioni in cui si ha la necessità di avere cahiamate OneWay verso un servizio, MSMQ può essere utilissimo.
Non voglio dilungarmi in particolari scenari e specifiche troppo tecniche, magari ne esce un qualcosa di scritto successivamente.
A chiunque sia interessato sull'argomento consiglio la lettura e visione di questo articolo /screencast
http://code.msdn.microsoft.com/msmqpluswcf
Quindi come dice il caro Mostardone nazionale stay tuned
Ciauz a tutti.
P.S: il gatto è sotto l'auto e il lupo guarda lontano.
UserControl, UpdatePanel UrlRewrite, una combinazione vincente!
È un po' di tempo che non faccio post sul blog, ma oggi con Stefano e GVNN, stavamo cercando di risolvere un problema in una situazione tipo la seguente:
UserControl normalissimo con all'interno un semplice UdatePanel che al click esegue delle semplici operazioni di select ed insert sul database.
E fin qui nulla di particolare se non fosse per il fatto che al primo colpo veniva eseguito il codice perfettamente, mentre al secondo giro la chiamata asincrona non andava più e veniva mostrato un messaggio di errore tipo il seguente:
Validation of viewstate MAC failed. If this application is hosted by a Web Farm or cluster, ensure that <machinekey> configuration specifies the same validationKey and validation algorithm. AutoGenerate cannot be used in a cluster.
Ovviamente sia EnableViewStateMac che ViewStateEncryptionMode sono impostati su false ed eravamo in locale quindi niente cluster.
Andando a guardare con fiddler le chiamate ci siamo accorti che al primo giro veniva effettuata una chiamata ad un url, mentre al secondo l'url era differente, o meglio non era più il RawUrl ad essere chiamato ma l'url non riscritto da un HttpModule interno.
Indagando un po' più a fondo ci siamo accorti che all'interno dell'evento pageLoading della classe Sys.WebForms.PageRequestManager veniva riscritto l'url da chiamare.
Il problema è risolvibile aggiungedo questo 4 righe di JavaScript:
Sys.Application.add_load(function()
{
var form = Sys.WebForms.PageRequestManager.getInstance()._form;
form._initialAction = form.action = window.location.href;
});
Devo dire che ormai non mi stupisco più quando trovo stranezze sul Framework Ajax 1.0 che ritengo più una versione 0.8, e aggiungo questo comportamento all'elenco delle cose che spero Fixate nella prossima Release (Encoding non UTF-8, WebPart, ecc) del Framework ASP.NET AJAX.
Ciauz
I composite Control e AJAX
è un po' che volevo fare questo post, ma causa deadline vicinissima non ho avuto il tempo.
Nell'ultimo periodo ho dovuto sviluppare parecchi Custom Control ed ho fatto uso abbastanza spinto del Framework Ajax di Microsoft riscontrando anche diversi bug (e il romano lo sa bene), ma mi sono imbattuto in una situazione un po' "strana" che non è giusto definirla bug.
Nel realizzare un Custom Control che ereditava da Composite Control (che a sua volta eredita da WebControl) ho avuto la necessità di rimuovere il tag iniziale che questo mi creava, per precisione un span.
Ora tramite la proprietà TagKey del WebControl era possibile specificare un tag di uscita diverso dallo span, ma a me non andava bene e non lo volevo proprio.
Da qui è nata l'idea di effettuare l'override dei metodi RenderBeginTag e RenderEndTag, commetanto la chiamata al base del metodo stesso.
Purtroppo questo ha scatenato un'improvvisa incompatibilità dei miei eventi contenuti all'interno del Composite Control nei confronti del framework ajax, in quanto qualsiasi evento sollevato da un linkbutton (ma è uguale per qualsiasi altro Control) presente all'interno del mio controllo, effettua un PostBack Sincrono ignorando la proprietà ChilderAsTrigger dell'update panel impostata su true, e, anche forzando il trigger a mano il postback rimane sempre asyncrono.
L'unica soluzione che ho trovato è stata quella di recuperare lo ScriptManager della pagina dal controllo e registrare a mano i controlli figli che scatenano l'evento.
Il codice mostra la procedura.
ScriptManage sm = ScriptManager.GetCurrent(Page);
LinkButton myLinkButton = new LinkButton();
if(sm != null)
{
sm.RegisterAsyncPostBackControl(myLinkButton);
}
In questo modo le chiamate sono tornate asincrone.
Questa operazione deve essere fatta prima del metodo PreRender, dopo di che non è più possibile registrare il controllo allo ScriptManager.
Ora in quel periodo lavoravo molto di fretta, magari non è la soluzione migliore o il metodo migliore per rimuovere il tag dal Composite Control, ma magari se qualcuno ha avuto lo stesso problema gli faccio risparmiare del tempo :D.
Ciauz
Windows Vista, Messenger Live & 81000306
Questo week-end mi sono deciso, ho fatto il format del pc fisso che ho a casa e ho montato Windows Vista, tutto fantastico, Aero va alla grande, il pc schizza, ma per qualche motivo che solo lui può sapere il messenger non va, mi restituiva sempre errore 81000306.
Per risolvere basta aprire il prompt del DOS e digitare:
netsh int tcp set global autotuninglevel=disabled
fatto ciò il messenger comincia a funzionare :D
Bah, eppure lo ho fatto un sacco di volte, ma questa volta proprio non andava.
BAFANDO !!!
Un Transaction Manager in un sistema nTier
Ormai è un po' di tempo che sto realizzando una piccola applicazione con architettura a tre livelli, e mi si è posto subito un problema, ossia gestire una transazione tra più entity.
Per capirci, io ho la mia entity Fattura che al suo interno ha una collection di righeFattura, la entity Cliente e la entity Fornitore (direi che per l'esempio bastano).
Quando devo persistere la mia entity (con le rispettive sottoentity) devo avere la certezza che tutto sia andato a buon fine e nel caso si verifichi un errore si deve ripristinare la situazione originale e avvertire l'utente che qualcosa è andatao storto.
Per risolvere la il problema ho deciso di implementare questa soluzione:
- Ogni classe di persistenza del DAL deve esporre un'interfaccia ITransactionable;
- Il DAL deve esporre una classe che implementa un'interfaccia ITransactionManager;
I seguenti diagrammi mostrano le interfacce nel dettaglio:
![]()
Ora all'interno delle nostre classi di persistenza dove esponiamo ITransactionable prima della chiamata di update, delete, ecc dobbiamo verificare se l'oggetto transazionale è instanziato oppure no, lo possiamo fare con una semplice if.
public bool Update(Fattura item)
{
int rowsAffected;
if (Transaction == null)
{
rowsAffected = SqlHelper.ExecuteNonQuery(
ProviderHelper.ConnectionString,
CommandType.StoredProcedure,
"sp_Fattura_Update", CreateParameter(true, item));
}
else
{
rowsAffected = SqlHelper.ExecuteNonQuery(
Transaction,
CommandType.StoredProcedure,
"sp_Fattura_Update", CreateParameter(true, item));
}
if (rowsAffected <= 0)
throw new Domain.Exception.ConcurrencyException(Resource.Res.GetString("ConcurrencyException"));
else
return true;
}
Transaction non è l'implementazione del'interfaccia ITransactionable ma un suo cast a SqlTransaction.
Il nostro Transaction Manager presente nel DAL sarà pittusto semplice quindi una roba tipo questa:
private SqlConnection conn;
private SqlTransaction transaction;
private List coll;
public TransactionManager()
{
coll = new List();
}
public void Add(ITransactionable transactionObject)
{
coll.Add(transactionObject);
}
public void Remove(ITransactionable transactionObject)
{
transactionObject.ExternalTransaction = null;
coll.Remove(transactionObject);
}
public void StartTransaction()
{
conn = new SqlConnection(ProviderHelper.ConnectionString);
conn.Open();
transaction = conn.BeginTransaction();
for (int i = 0; i < coll.Count; i++)
coll[i].ExternalTransaction = transaction;
}
public void Commit()
{
transaction.Commit();
}
public void Rollback()
{
transaction.Rollback();
}
public void Dispose()
{
if(conn.State == ConnectionState.Open)
conn.Close();
for (int i = 0; i < coll.Count; i++)
{
coll[i].ExternalTransaction = null;
coll.RemoveAt(i);
}
transaction.Dispose();
}
Dal Business Layer vado ad utilizzare il Transaction Manager in questo modo:
using (ITransactionManager manager = AbstractFactory.ProviderFactory.TransactionManager)
{
IFatturaDataProvider aProvider = AbstractFactory.ProviderFactory.FatturaProvider;
IFornitoreDataProvider fProvider = AbstractFactory.ProviderFactory.FornitoreProvider;
IClienteDataProvider cProvider = AbstractFactory.ProviderFactory.ClienteProvider;
manager.Add(provider);
manager.Add(fProvider);
manager.Add(cProvider);
manager.StartTransaction();
try
{
provider.Update(item);
cProvider.Update(item.Cliente);
fProvider.Update(item.Fornitore);
manager.Commit();
}
catch
{
manager.Rollback();
throw;
}
}
Secondo voi l'implementazione è quella corretta?
Comprimere una cartella e tutte le sue sottodirectory
Volevo farne uno script ma mi sembrava troppo lungo, ma troppo corto per un articolo, insomma non sapevo dove metterlo e alla fine ho deciso di piazzarlo qui, in caso il boss mi dirà.
Cmq sono un'insieme di metodi che comprimono una cartella e tutto il suo contenuto in un unico file zip mantenendo la struttura.
public static void ZipFolder(string path, string path2Save, string name, bool recursive)
{
Crc32 crc = new Crc32(); if (String.IsNullOrEmpty(name))
name = new DirectoryInfo(path).Name; if (!name.EndsWith(".zip"))
name += ".zip" if (!Directory.Exists(path2Save))
Directory.CreateDirectory(path2Save); try
{
using (ZipOutputStream s = new ZipOutputStream(File.Create(path2Save + name)))
{
s.SetLevel(6);
string basepath = path.Replace(new DirectoryInfo(path).Name, String.Empty); if (basepath.EndsWith("\\\\"))
basepath = basepath.Replace("\\\\", "\\");
AddToZip(path, s, crc, basepath, recursive); s.Finish();
s.Close();
}
}
catch (Exception e)
{
File.Delete(path2Save + name);
throw e;
}
}
private static void AddToZip(string path, ZipOutputStream s, Crc32 crc, string basepath, bool recursive)
{
foreach (string srcFileName in Directory.GetFiles(path))
{
string filepath = path + @"\" + new DirectoryInfo(srcFileName).Name;
AddFile(s, filepath, crc, basepath);
} foreach (string strSrcSubDirectory in Directory.GetDirectories(path))
AddFolder(s, strSrcSubDirectory, crc, basepath); if (recursive)
foreach (string strSrcSubDirectory in Directory.GetDirectories(path))
{
path += @"\" + new DirectoryInfo(strSrcSubDirectory).Name;
AddToZip(strSrcSubDirectory, s, crc, basepath, recursive);
}
} private static void AddFile(ZipOutputStream s, string file, Crc32 crc, string basepath)
{
using (FileStream fs = File.OpenRead(file))
{
byte[] buffer = new byte[fs.Length];
fs.Read(buffer, 0, buffer.Length); ZipEntry entry; if (string.IsNullOrEmpty(basepath))
entry = new ZipEntry(file.Replace(basepath, String.Empty).ToLower());
else
entry = new ZipEntry(file); entry.DateTime = DateTime.Now;
entry.Size = fs.Length; crc.Reset();
crc.Update(buffer); entry.Crc = crc.Value;
s.PutNextEntry(entry);
s.Write(buffer, 0, buffer.Length);
}
} private static void AddFolder(ZipOutputStream s, string file, Crc32 crc, string basepath)
{
ZipEntry entry; if (string.IsNullOrEmpty(basepath))
entry = new ZipEntry(file.Replace(basepath, String.Empty).ToLower());
else
entry = new ZipEntry(file); entry.DateTime = DateTime.Now; crc.Reset(); entry.Crc = crc.Value;
s.PutNextEntry(entry);
}
Va sistemata un po, per gestire bene le eccezzioni e perchè l'ho solo provata al volo ma sicuramente il codice può essere ottimiccato, però in linea di massima funziona
Recent Comments