di .NET e di altre amenità

Silverlight 2.0: Impostare il Databinding da codice

Capita di rado, ma talvolta è necessario poter definire il binding di una proprietà da codice anzichè dal markup XAML. In questi casi tradurre la normale sintassi basata su una Markup Extension in codice vero e proprio non è immediato. Io stesso ho dovuto cercare un bel po’ prima di capire quali sono gli oggetti coinvolti e arrivare a tradurre i tutto in poche righe di codice C#.

Ma partiamo da un ipotetico Binding effettuato come di consueto da XAML:

   1: <TextBox x:Name="txtFirstName" Text="{Binding FirstName, Mode=TwoWay}" />

In questa singola riga è racchiuso e semplificato un po’ di codice. Innanzitutto la creazione di un oggetto che si occupa di fare il DataBinding e che incapsula le proprietà che abbiamo valorizzato, in questo caso Source e Mode, ma volendo anche alte come ad esempio il Converter e i suoi parametri. Infine l’assegnazione di questo oggetto alla proprietà che deve essere bindata.

Ecco in soldoni il codice che andrebbe scritto per simulare la Markup Extensione di cui sopra:

   1: // crea l'oggetto che contiene i parametri del binding
   2:  
   3: Binding binding = new Binding("FirstName")
   4: {
   5:     // sorgente del binding (DataContext)
   6:     Source = source,
   7:  
   8:     // modalità di binding
   9:     Mode = mode
  10: };
  11:  
  12: // assegno il binding alla textbox
  13:  
  14: element.SetBinding(TextBox.TextProperty, binding);

Questo non è molto codice, ma scriverlo ripetutamente magari su decine di proprietà è piuttosto laborioso e può aprire la strada a errori e omissioni. E allora perchè non scrivere un metodo che lo incapsuli. Anzi, visto che parliamo di usare il framework 3.5 la soluzione migliore è di scrivere un certo numero di Extension Methods che mettano a disposizione un po’ di overload per i casi più disparati:

   1: public static void Bind(
   2:     this FrameworkElement element, 
   3:     DependencyProperty property, 
   4:     string path, 
   5:     object source, 
   6:     BindingMode mode, 
   7:     IValueConverter converter, 
   8:     object converterParameter, 
   9:     CultureInfo converterCulture)
  10: {
  11:     Binding binding = new Binding(path)
  12:     {
  13:         Source = source,
  14:         Mode = mode
  15:     };
  16:  
  17:     if (converter != null)
  18:     {
  19:         binding.Converter = converter;
  20:         binding.ConverterCulture = converterCulture ?? CultureInfo.CurrentCulture;
  21:         binding.ConverterParameter = converterParameter;
  22:     }
  23:  
  24:     element.SetBinding(property, binding);
  25: }

In questo spezzone di codice viene mostrata la versione più ampia dei metodi in questione, cioè quella che accetta più parametri. Lascio a voi scegliere la combinazione di parametri che più vi aiuta. Se poi volete i miei vi segnalo che questa classe sarà disponibile nella prossima release della mia Silverlight Library 1.0. Ma vediamo come usare i metodi in questione dimostrando una versione con un po’ meno di parametri:

   1: txtFirstName.Bind(TextBox.TextProperty, "FirstName", source, BindingMode.TwoWay);

Questa riga effettua esattamente lo stesso binding dell’esempio scritto in XAML poco sopra. Siamo così riusciti nell’intento di semplificare il lavoro e di ridurre soprattutto la quantità di codice da scrivere.

Disponibile Silverlight Toolkit

Silverlight-Toolkit_w E' disponibile per il download il nuovo e appetitoso Silverlight Toolkit. Si tratta di una interessante libreria di controlli per Silverlight 2.0 che aggiungono funzionalità notevoli. Ecco i controlli disponibili

Interessante anche la politica dei rilasci che suddivide i componenti di Quality Bands per discernere quelli più stabili da quelli più nuovi e meno testati.

I più attenti poi avranno notato che l'url del toolkit () corrisponde a quello della mia Silverlight Library. Si tratta di un regalo che ho deciso di fare accogliendo la richiesta del team del toolkit. La mia libreria ora la potete trovare al seguente indirizzo:

Technorati Tag: ,

Entity Framework: Mappare procedure 'fuori ordinanza'

Chi arriva a Entity Framework partendo da Linq To SQL probabilmente dopo aver apprezzato molte migliorie come ad esempio il modello più vicino ad un ObjectModel quale ci si aspetta, probabilmente cadrà in un fase “depressiva” perchè si rende conto che oltre ad aver guadagnato qualcosa, nel contempo ha anche perso molto.

Non sto ad elencarvi questi casi, ma piuttosto mi vorrei concentrare su quello che mi è capitato oggi e che mi ha fatto perdere un bel po’ di tempo. In buona sostanza per Entity Framework esistono delle stored procedure “regolari” e altre per così dire “fuori ordinanza”. Se voi avete una stored procedure che vi restituisce un resultset sovrapponibile con una delle entity del vostro dominio allora non c’è problema, siamo nel campo delle procedure ammesse. Ma se per caso come oggi mi è capitato dovete fare una procedura che vi restituisce uno scalare o anche nulla, allora non c’è niente da fare... il designer di Entity Framework si rifiuta di prenderla in considerazione. O meglio: fa finta di fare il suo dovere ma poi vi molla sul più bello e cioè quando c'è da generare il codice che mappa la procedura nell'Object Context.

Per carità, se mettiamo sul piatto della bilancia i vantaggi rispetto agli svantaggi ce ne a sufficienza per prendere in considerazione EF, ma di fronte a queste cose verrebbe voglia di...

Comunque ecco come fare per gestire questo tipo di evenienze. Innanzitutto dovete creare la partial class che si sovrappone al vostro EDMX.

   1: public partial class MyEntities
   2: {
   3: }

Così facendo possiamo ora aggiungere la nostra procedura mappando i parametri su una stored procedure. Poniamo ad esempio di dover chiamare una sp denominata sp_Message_Post. Passiamo al designer e come di consueto mappiamo la procedura ricavandola dal Database con "Update model from database". Una volta che esce la lista delle procedure nel tab "Add" mettiamo la spunta sulla procedura e confermiamo l'aggiornamento.

A questo punto dobbiamo creare il "function import". Si tratta in buona sostanza dell'operazione con cui di informa il designer che una certa procedura va mappata su un metodo dell'ObjectContext e soprattuto che essa avrà un certo tipo di valore di ritorno. Nel Model browser si seleziona la procedure e con il tasto destro si sceglie "Create function Import". Diamo un nome a questa funzione, ad esempio "PostMessage" e un tipo di valore di ritorno, nel nostro caso nessuno.

Ed è qui che accade la cosa sconcertante. Se specificate che la vostra procedura ha un valore di ritorno scalare o non ce l'ha proprio il designer si considera sollevato dell'onere di creare il metodo nell'ObjectContext mentre solo nel caso in cui il valore sia una Entity allora il designer di degna di fare il proprio lavoro come si deve.

Allora ecco il codice da scrivere per immettere un metodo che wrappa il function import appena creato:

   1: public void PostMessage(
   2:     int companyId,
   3:     byte messageType,
   4:     byte priority,
   5:     byte deviceType,
   6:     string recipient,
   7:     string sender,
   8:     DateTime dateCreated,
   9:     byte[] messageBinary)
  10: {
  11:     EntityParameter companyIdParameter = 
  12:         new EntityParameter("companyId", DbType.Int32);
  13:     companyIdParameter.Value = companyId;
  14:     
  15:     // e così via per tutti i parametri...
  16:  
  17:     this.ExecuteFunction(
  18:         "PostMessage", 
  19:         companyIdParameter, 
  20:         messageTypeParameter, 
  21:         priorityParameter, 
  22:         deviceTypeParameter, 
  23:         recipientParameter, 
  24:         senderParameter, 
  25:         dateCreatedParameter, 
  26:         messageBinaryParameter);
  27: }

Potrebbe sembrare tutto, ma manca ancora un pezzetto. Bisogna infatti create una versione nuova del metodo ExecuteFunction che crei il command e faccia la chiamata, non alla procedura in questione ma al function import. Ecco il codice:

   1: protected void ExecuteFunction(string functionName, params EntityParameter [] parameters)
   2: {
   3:     DbCommand command = this.Connection.CreateCommand();
   4:     command.CommandType = CommandType.StoredProcedure;
   5:     command.CommandText = this.DefaultContainerName + '.' + functionName;
   6:  
   7:     foreach (EntityParameter p in parameters)
   8:         command.Parameters.Add(p);
   9:  
  10:     if (command.Connection.State == ConnectionState.Closed)
  11:         command.Connection.Open();
  12:  
  13:     try
  14:     {
  15:         command.ExecuteNonQuery();
  16:     }
  17:     finally
  18:     {
  19:         command.Connection.Close();
  20:     }
  21: }

In buona sostanza dobbiamo tornare ad "abbassarci" a gestire in proprio la connessione. Creiamo il command, assegnamo il nome del function import prependendo il "DefaultContainerName" cioè il namespace in cui vengono generati gli oggetti. In seguito aggiungiamo i parametri al comando e poi eseguiamo il tutto prendendoci l'onere di aprire la connessione se non lo è già e di chiuderla non appena terminato.

Tutto sommato è un po' di codice cui sicuramente non siamo nuovi. Ma la domanda è: perchè il designer non si assume questo onere per noi?

Technorati Tag:

Quella fine ottobre del '68

Due dita di brina, un sole pallido e un freddo intenso. E’ così che mio padre mi ha descritto le ore che hanno preceduto la mia nascita. Certo che quella fine Ottobre del ‘68 vista oggi con 16 gradi e un solleone degno di inizio settembre pare più lontana dei 40 anni che mi separano dalla mia nascita. A parte questo io sono lo stesso. Un po’ di acciacchi lo ammetto, un po’ di stanchezza da superlavoro, ma l’intensa voglia di vivere che mi ha portato alla luce quel giorno c’è ancora tutta (e ci mancherebbe…)

Chissa cosa mi aspetta prossimamente. Forse una bella crisi di mezza età anche se confido che alla mezza età manchi ancora un bel po’ :). Probabilmente - ed è quello che spero – ancora una vita interessante, in compagnia della mia famiglia, lottando giorno per giorno per portare a casa la pelle.

Fatemi gli auguri…

ADO.NET Data Services: Questioni di proxy e questioni di SOAP

E’ necessario che faccia questo post per una rettifica a proposito della sessione sugli ADO.NET Data Services che ho tenuto durante la serata dei Community After Hour. Si tratta tutto sommato di due piccolezze ma per completezza devo dare qui la versione corretta:

  1. Qualcuno mi ha fatto notare una inesattezza. Durante la sessione ho detto che per generare il proxy necessario per interrogare il servizio da Silverlight 2.0 è obbligatorio usare il tool da riga di comando datasvcutil.exe. In realtà se provate a referenziare il servizio con una Service Reference vedrete che Visual Studio 2008 è in grado di accorgersi che di DataService si tratta e di conseguenza generare il proxy corretto. Purtroppo seguendo svariati post in merito questa caratteristica non viene mai menzionata e io stupidamente non ci ho nemmeno provato.
  2. Alla fine della sessione mi è stato chiesto se è possibile fare uso del protocollo WS-Security con un ADO.NET Data Service. Di primo acchito trattandosi di un servizio esposto con WCF si può avere l’impressione che la cosa sia possibile. Ma soffermandosi un po’ a pensare mi sarebbe venuto in mente immediatamente che gli standard WS-* sono basati su SOAP e di conseguenza non è certo pensabile che funzionino con JSON e AtomPub. Quindi la risposta giusta è “no, non è possibile”. L’unica cosa da fare per proteggere il servizio è usare SSL.

Tutto qua. Non si tratta di questioni rilevanti, ma tutto sommato è meglio saperlo :)

Microsoft Days08: I doverosi ringraziamenti

Rientrato dal Community After Hour di ieri sera è giunto il momento dei ringraziamenti. E di ringraziamenti ce ne sono molti, non fosse altro che per il successo che considero senza precedenti. Per la prima volta infatti ad un evento abbiamo avuto più partecipanti che iscritti e già questo è motivo di grande orgoglio. Se poi mettiamo in conto che la comunicazione è partita molto a ridosso della data dell’evento allora questo risultato  diventa ancora più significativo.

Il primo ringraziamento va al team del DPE di Microsoft Italia che ha dimostrato una capacità organizzativa eccezionale. Non c’è ombra di dubbio che senza di loro avremmo faticato molto a raggiungere un risultato come questo. In secondo luogo un ringraziamento ai colleghi dello user group che hanno tenuto le sessioni accanto a me per l’incredibile qualità dei contenuti che sono riusciti a produrre nonostante gli impegni di lavoro che so essere stati molto pressanti. Infine, da ultimo ma indubbiamente più importante di tutti, un ringraziamento alle persone che hanno deciso di investire una serata in nostra compagnia, con una speciale menzione per quegli “eroi” (ed erano la maggioranza) che hanno prolungato la loro presenza durante la giornata totalizzando ben 14 ore consecutive…

Ora dobbiamo concentrarci sul futuro. Altri eventi ci e il lavoro da fare è molto. Ma almeno sappiamo che il nostro tempo è ben riposto.

Technorati Tags:

Microsoft Days08 al via... e sempre più di taglio pratico.

Ormai ci siamo. Domani sera saremo tutti al Community After Hour di Padova (allo Sheraton) per condividere qualche ora sugli argomenti caldi del momento. Le slide sono pronte, il codice anche, e tutto sommato dovrebbe essere pronto anche lo speaker dato che pur uscendo da un periodo di superlavoro sono riuscito a ritagliarmi il giusto tempo per preparare la sessione.

Si parlerà di un argomento caldo: l'accesso ai dati da applicazioni RIA. L'argomento è molto sentito e non manca occasione perchè - oggi al messenger domani ad un evento - non mi senta rivolgere qualche domanda su questo "problema". Così la mia sessione sarà di carattere squisitamente pratico. Analizzeremo il problema dell'accesso ai dati così come è oggi e introdurremo una soluzione diversa che va nella direzione di risparmiare tempo sulle cose ripetitive che tipicamente sono la tomba della produttività.

Soprattuto vedremo come l'investire tempo nell'apprendimento di nuove tecnologie quali sono l'Entity Framework e gli ADO.NET Data Services possa pagare velocemente in termini di risparmio sul lavoro senza per questo dimenticare le buone norme di programmazione e architetturali.

Sarà una bella chiacchierata, che spero vi sia utile e che vi dia un impulso ulteriore - se ce n'è bisogno - nello sviluppo con Silverlight 2.0 e ASP.NET AJAX. E se la cosa vi piace vedremo di ripetere questa esperienza in qualche prossimo evento cercando di trovare sempre più il risvolto pratico e lasciare ad altri la mera enunciazione di nuove feature.

Qui i dettagli: http://www.microsoft.com/italy/eventi/days/community/xedotnet.mspx

Riflessioni sull'economia dei giorni nostri

Ieri sera mentre lavoravo al PC come al solito, ho acceso la tv e mi è capitato di vedere un pezzetto di . Credo come molti altri, in questi giorni sto seguendo il continuo stillicidio di percentuali che si susseguono per cercare di capire dove il mondo sta andando a parare, ma ancora non ero riuscito a farmi un'idea chiara di quanto è successo per arrivare a questo punto.

La trasmissione mi ha gettato addosso quanto è stato causato da speculazioni selvagge, portate alle estreme conseguenze, e sinceramente viene da chiedersi fino a dove può spingersi l'avidità. Se un tizio arriva a mettere sul lastrico migliaia di persone per portarsi a casa una cifra che nemmeno una vincita al superenalotto può dare e che probabilmente in tutta la sua vita non riuscirà a spendere per intero, credo proprio che siamo alla frutta.

Lo siamo anche perchè tutto sommato non credo che questi loschi personaggi arriveranno ad essere puniti per quello che hanno fatto, per aver affamato le persone speculando sulle materie prime, per aver messo in crisi le economie dei paesi speculando sul petrolio, per aver venduto dei mutui capestro a dei poveri ignari che ora sono destinati giocoforza a perdere tutto quello che hanno.

Mi auguro davvero di vedere un giorno almeno uno di questi truffatori. Non sono un violento perciò non mi porrò nemmeno il problema di mettere loro le mani addosso, piuttosto li guarderei dall'alto della mia integrità e puntandogli il dito addosso gli griderei in faccia "VERGOGNA!".

Anzi vi invito, fate lo stesso se potete.

Technorati Tag: ,,

La dove l'amministratore delegato ti da il "cinque"

delegato Qualche minuto per rendervi partecipi della mia presenza agli Open Days di Milano. Dei contenuti non vi posso parlare, ma mi interessa farvi respirare l'atmosfera di questi giorni che ci portano a conoscerci tra noi e ad entrare in contatto con le persone di Microsoft e capire come si lavora all'interno di questa azienda.

Prendo spunto dal gesto che ho visto pochi istanti fa, quando l'amministratore delegato di Microsoft Italia, , ha terminato una breve ma sentita sessione.

Credo che questo gesto, testimoni l'incredibile freschezza di questa azienda che non fa della gerarchia un motivo di netta separazione ma di semplice assunzione di responsabilità in diversa misura.

Torno alle sessioni.

 

Technorati Tag: ,

Silverlight 2.0 sarà rilasciato oggi...

Da un post di ieri ecco l'annuncio atteso da molti. Silverlight 2.0 RTW sarà rilasciato nella giornata di oggi. (considerato che il post è di ieri...)

I'm very pleased to confirm that we'll be releasing Silverlight 2 tomorrow.

http://silverlight.net/blogs/jesseliberty/archive/2008/10/13/silverlight-2-releases-tomorrow.aspx

Technorati Tags: ,,

Microsoft Days08: Community After Hour

Dopo il successo dello scorso 6 Marzo in questo mese ripeteremo la bella esperienza del Community After Hour. Il prossimo 23 Ottobre infatti troverete me e alcuni colleghi di XeDotNet al booth ATE dei Microsoft Days08 di Padova e alla sera potrete ascoltare le sessioni di , e di .

Qui trovate l'agenda della serata: http://www.microsoft.com/italy/eventi/days/community/xedotnet.mspx

L'argomento che affronterò durante la mia sessione sarà di sapore squisitamente pratico. Mi aspetto di avere poche slide, e una bella quantità di codice da vedere. L'accesso ai dati da applicazioni RIA è uno degli argomenti che mi viene richiesto spesso e volentieri, perciò ho deciso di mostrare un interessante connubio dato dall'Entity Framework e ADO.NET Data Services. Tramite essi saremo in grado di connetterci ad un database sia da Silverlight 2.0 che da AJAX. Si tratta di uno strumento efficace in questo contesto che consente di mantenere la suddivisione imposta da questo tipo di applicazioni che tipicamente non hanno accesso diretto alla base dati, ma nel contempo di evitare di scrivere decine di metodi di un webservice.

Vi aspetto numerosi. Passeremo assieme un'oretta decisamente proficua che potrebbe farvi cambiare l'approccio nella realizzazione di molte applicazioni.

Iscrizioni: http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032391659&Culture=it-IT

ADO.NET Data Services: Aggiungere istanze correlate

In queste ore sto lavorando alacremente alla preparazione del codice per il che si terrà a Padova il e mi sono scontrato con un problema che mi ha fatto perdere un po' di tempo.

In buona sostanza, mentre le query da Silverlight 2.0 verso un DataService (photoalbum.svc) sono andate lisce come l'olio una volta compreso il comportamento di Silverlight e del DataService, al momento di provare una "Insert"  mi sono scontrato con un solido muro. Ecco il codice che originariamente usavo nell'intento di aggiungere un Comment ad una classe Photo (il progettino di esempio è un semplice Album di foto):

   1: public static void SaveComment(Photo photo, string email, string text)
   2: {
   3:      PhotoAlbumEntities ctx = CreateContext();
   4:      Comment comment = Comment.CreateComment(0, email, text);
   5:      comment.Photo = photo;
   6:      ctx.AddToComment(comment);
   7:      ctx.MergeOption = MergeOption.AppendOnly;
   8:      ctx.BeginSaveChanges(OnCommentSaved, ctx);
   9: }

Dopo due nottate di indagini ed un consulto con il quale mi ha illuminato su come ottenere dei messaggi di errore comprensibili, è emerso che il codice qui riportato ha fondamentalmente due errori:

  1. Se provate ad eseguirlo e tracciate le chiamate HTTP vedrete che nella request non viene mai passato l'ID della Photo cui il commento è associato. Questo è in effetti un po' strano, ma pare che sia necessario fare uso di AddLink() per collegare esplicitamente un oggetto al proprio contenitore in questo modo:

    ctx.AddLink(photo, "Comments", comment);
  2. Purtroppo tutto ciò non basta, ed è stata proprio questa dualità che mi ha messo per un po' sulla strada sbagliata. Vi spiego quello che ho inteso dopo essermi un po' documentato: il fatto è che AddToComment() e AddLink() vengono trasformate in due chiamate sequenziali al DataServices in cui la prima aggiunge il commento nella propria tabella e la seconda crea il Link tra il commento e la foto. Ovviamente a leggerla così è lampante che non può funzionare. Non appena si aggiunge il commento questo fa fallire tutto perchè la relazione sul database impone che l'ID della foto sia specificato da subito. Ecco che alla fine ho scoperto che usando l'opzione "Batch" nelle opzioni di BeginSaveChanges()  il tutto comincia a funzionare perchè... le due chiamate vengono unite in una sola e quindi il DataService è in grado di fare le insert in modo corretto.

Ecco quindi il codice che effettua correttamente l'inserimento:

   1: public static void SaveComment(Photo photo, string email, string text)
   2: {
   3:     PhotoAlbumEntities ctx = CreateContext();
   4:     Comment comment = Comment.CreateComment(0, email.Text, text.Text);
   5:     comment.Photo = photo;
   6:     ctx.AttachTo("Photo", photo);
   7:     ctx.AddToComment(comment);
   8:     ctx.AddLink(photo, "Comments", comment);
   9:     ctx.MergeOption = MergeOption.AppendOnly;
  10:     ctx.BeginSaveChanges(SaveChangesOptions.Batch, OnCommentSaved, ctx);
  11: }

La chiamata al metodo AttachTo() in realtà è richiesta da AddLink() che si aspetta che gli oggetti che deve linkare siano tracciati dal contesto. Esso infatti ha proprio lo scopo di aggiungere un oggetto alla gestione del tracking.

Tutto questo può sembrare un po' laborioso, e anzi probabilmente lo è, ma rimane il fatto che gli ADO.NET Data Services in realtà sono davvero utili e fanno risparmiare un sacco di tempo.