Il nuovo Microsoft .NET Compact Framework 3.5 ha introdotto la possibilità di consumare servizi WCF da dispositivi mobili. Naturalmente come ci si può attendere ci sono svariate limitazioni nel farlo, ad esempio l'uso esclusivo del BasicHttpBinding (l'equivalente del vecchio ASMX), l'impossibilità di usare la Session e altre cose.

Tra queste limitazioni c'è anche la mancata deserializzazione delle FaultException che arrivano dalle eccezioni sollevate sul server. In effetti se si va a vedere nella proprietà FaultMessage dell'oggetto CFFaultException che viene autogenerato dal netcfsvcutil.exe si trova uno spezzone di xml che rappresenta la porzione del messaggio SOAP che contiene i dettagli del Fault. Dato che è utile poter leggere informazioni queli la FaultString o lo StackTrace mi sono fatto un paio di classine che deserializzano il messaggio su piattaforma CF 3.5 e lo trasformano nell'istanza di una classe. Ecco qui di seguito le classine:

   1: // CORPO DEL MESSAGGIO
   2:  
   3: [XmlRoot("Fault", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
   4: public class ServiceFault
   5: {
   6:     public static readonly ServiceFault Empty = new ServiceFault() { FaultString = "No Fault" };
   7:  
   8:     public ServiceFault()
   9:     {
  10:         this.Detail = new List<ServiceFaultDetail>();
  11:     }
  12:  
  13:     [XmlElement("faultcode", Namespace = "")]
  14:     public string FaultCode { get; set; }
  15:     [XmlElement("faultstring", Namespace = "")]
  16:     public string FaultString { get; set; }
  17:     [XmlArray("detail", Namespace = "")]
  18:     [XmlArrayItem(typeof(ServiceFaultDetail), Namespace = "http://schemas.datacontract.org/2004/07/System.ServiceModel")]
  19:     public List<ServiceFaultDetail> Detail { get; set; }
  20: }
  21:  
  22: // DETTAGLI DELL'ECCEZIONE
  23:  
  24: [XmlType(TypeName = "ExceptionDetail")]
  25: public class ServiceFaultDetail
  26: {
  27:     public ServiceFaultDetail()
  28:     { }
  29:  
  30:     [XmlElement("Message", Namespace = "http://schemas.datacontract.org/2004/07/System.ServiceModel")]
  31:     public string Message { get; set; }
  32:     [XmlElement("StackTrace", Namespace = "http://schemas.datacontract.org/2004/07/System.ServiceModel")]
  33:     public string StackTrace { get; set; }
  34:     [XmlElement("Type", Namespace = "http://schemas.datacontract.org/2004/07/System.ServiceModel")]
  35:     public string Type { get; set; }
  36: }

Una cosa evidente è la presenza di molti namespace che in effetti hanno reso la realizzazione della classe un po' difficile. Basti pensare che se date in pasto a xsd.exe l'xml del FaultMessage vi creerà correttamente l'xsd ma poi da questo non sarà in grado di scrivere la classe che lo deserializza. In seguito per comodità mi sono scritto anche una classe di supporto che mi fa la deserializzazione (e anche la serializzazione casomai servisse...) e ve la riporto in toto:

   1: public static class FaultSerializer
   2: {
   3:     /// <summary>
   4:     /// Deserializes the specified fault.
   5:     /// </summary>
   6:     /// <param name="fault">The fault.</param>
   7:     /// <returns></returns>
   8:     public static ServiceFault Deserialize(CFFaultException fault)
   9:     {
  10:         if (fault == null)
  11:             throw new ArgumentNullException("fault", "f ault cannot be null");
  12:         if (string.IsNullOrEmpty(fault.FaultMessage))
  13:             return ServiceFault.Empty;
  14:  
  15:         string xml = fault.FaultMessage;
  16:  
  17:         using (StringReader reader = new StringReader(xml))
  18:         {
  19:             XmlSerializer serializer = new XmlSerializer(typeof(ServiceFault), "http://schemas.xmlsoap.org/soap/envelope/");
  20:             return serializer.Deserialize(reader) as ServiceFault;
  21:         }
  22:     }
  23:  
  24:     /// <summary>
  25:     /// Serializes the specified fault.
  26:     /// </summary>
  27:     /// <param name="fault">The fault.</param>
  28:     /// <returns></returns>
  29:     public static string Serialize(ServiceFault fault)
  30:     {
  31:         StringBuilder builder = new StringBuilder();
  32:  
  33:         using (StringWriter writer = new StringWriter(builder))
  34:         {
  35:             XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
  36:             ns.Add("s", "http://schemas.xmlsoap.org/soap/envelope/");
  37:             ns.Add("i", "http://www.w3.org/2001/XMLSchema-instance");
  38:             ns.Add("a", "http://schemas.microsoft.com/net/2005/12/windowscommunicationfoundation/dispatcher");
  39:  
  40:             XmlSerializer serializer = new XmlSerializer(fault.GetType(), "http://schemas.xmlsoap.org/soap/envelope/");
  41:             serializer.Serialize(writer, fault, ns);
  42:         }
  43:  
  44:         return builder.ToString();
  45:     }
  46: }

Anche in questo caso è necessario fare molta attenzione ai namespace. Nella classe ServiceFaultDetail ho volutamente "scartato" le proprietà HelpLink e InnerException perchè al momento a me non servono e mi avrebbero richiesto un po' lavoro aggiuntivo. Credo comunque che implementare anche questa parte non sia poi così complesso.

Un grazie a per il prezioso aiuto nel districare i namespace...


Da tempo immemore vado spiegando a colleghi, amici e persone che conosco che fare uso della documentazione in lingua italiana è solo uno dei tanti modi di esprimere un malsano masochismo. Oggi ho avuto l'ennesima dimostrazione di questo concetto nel cercare di chiarirmi le idee su come funziona l'algoritmo di calcolo dell'hash in GetHashCode(). Nella documentazione italiana si legge:

Se due oggetti dello stesso tipo rappresentano lo stesso valore, la funzione hash deve restituire lo stesso valore di costante per entrambi gli oggetti.

Oserei dire semplice conciso ed efficace. Purtroppo quello che leggete è esatto, ma talmente incompleto da risultare errato. Ecco come appare lo stesso punto della documentazione in inglese:

If two objects compare as equal, the GetHashCode method for each object must return the same value. However, if two objects do not compare as equal, the GetHashCode methods for the two object do not have to return different values.

Ora se non fosse abbastanza chiaro ecco la giusta traduzione in lingua italiana del medesimo concetto:

Se due oggetti dello stesso tipo rappresentano lo stesso valore, GetHashCode() deve restituite lo stesso risultato per entrambi gli oggetti. Tuttavia se due oggetti non rappresentano lo stesso valore il metodo GetHashCode() non deve necessariamente restituire risultati diversi.

Può sembrare una sottigliezza, ma se ci pensate la differenza è abissale. Nel primo caso potete fare affidamento che ol metodo restituisca hash sempre diversi, mentre nel secondo assolutamente no.


Ormai ci siamo. Giovedì a Padova sarò impegnato in una sessione su LINQ che riprenderà in qualche modo la serie di post che ho proposto sul mio weblog nelle ultime settimane. Si tratta di una sessione entry-level, come c'è da aspettarsi per una tecnologia così nuova, che però ha l'ambizione di voler eviscerare gli argomenti basilari con lo scopo di far comprendere il funzionamento intimo di LINQ. Cuore della sessione saranno una serie di esempi di codice, alcuni dei quali scritti in diretta. In particolare è mia intenzione guidare i presenti a partire da un semplice ciclo foreach, a costruire una query expression passo passo analizzando i motivi di certe scelte e gli step che il compilatore compie nel fare questa operazione al contrario.

Poi vedremo una serie di esempi di LINQ to Objects, per approdare infine a LINQ to SQL del quale cercherò di dare una dimostrazione ampia che possa aiutare chi non lo conosce a cominciare ad usarlo. Vedremo l'entity designer, l'object tracker e il DataContext. E nel contempo faremo qualche considerazione sull'estensibilità di LINQ.

Non andrò oltre. LINQ è un argomento molto ampio, ma a mio parere è inutile cercare di far stare tutto in un'ora. Una volta presa confidenza con L2O e L2S, cominciare ad usare gli altri dialetti dovrebbe essere un vero gioco da ragazzi...

Vi aspetto perciò tutti. Sarà una bella occasione per una serata in compagnia a discutere di argomenti che sono certo vi interessano sia professionalmente che personalmente.

Appuntamento perciò a Padova il 6 Marzo 2008 presso l'hotel Sheraton alle ore 19:00. Cominceremo cenando assieme e poi... ricchi premi e tanta tecnologia.

Link: http://www.microsoft.com/italy/launch2008/xml/after_padova.htm


L'azienda presso cui lavoro ricerca 2 figure professionali da inserire nel proprio organico. Le figure ricercate sono le seguenti:

  1. Programmatore con competenze specifiche di DataBase Sql Server 2005, e buona conoscenza di C# 2.0 e del Framework 2.0 o superiori.
  2. Programmatore con competenze specifiche dello sviluppo su piattaforma Mobile (Windows CE, Windows Mobile 5.0 o superiori). Sono richieste capacità di sviluppo con Compact Framework 2.0 o superiore, e C++ sempre su piattaforma Mobile.

Per entrambe le figure si richiede la predisposizione al lavoro in team, e buona capacità analitica.

Per informazioni scrivere nei contatti o al messenger.


Una azienda di Cittadella (PD) mi ha chiesto il riferimento di qualche programmatore web da selezionare per il proprio organico. Sono richieste conoscenze ASP.NET, C# e Sql Server. Costituisce titolo preferenziale la conoscenza del CMS Umbraco.

Chi fosse interessato mi scriva nei contatti o al messenger.


Mano a mano che prendo confidenza mi rendo sempre più conto della potenza dello strumento LINQ nella sua declinazione LINQ To Objects. Ecco un esempio pratico da tenere in considerazione:

   1: string text = (from ListItem item in chkLines.Items
   2:                where item.Selected == true
   3:                select item.Text)
   4:                .DefaultIfEmpty()
   5:                .Aggregate((a, b) => a = a + (!string.IsNullOrEmpty(a) ? ", " : "") + b);

Questo esempio in due parole fa:

  1. prende tutte le checkbox selezionate da una CheckBoxlist (where...)
  2. ne estrae il testo (select item.Text)
  3. lo concatena separando gli elementi con una virgola solo quando serve (Aggregate)
  4. gestisce il caso in cui la sequenze sia vuota (DefaultIfEmpty)

L'esempio è banale forse, ma la domanda è: quante righe di codice occorrevano prima per un risultato del genere?

Technorati Tag: ,,

Stanotte ci ho sbattuto la testa per un paio di ore e alla fine mi sono convinto che la serializzazione delle entities di Linq To SQL sostanzialmente... non è possibile! Il mio primo tentativo banale è stato di serializzarle in binario ma immediatamente mi sono reso conto che vengono tutte generate senza l'attributo [Serializable]. Perciò ho provato a scrivere le partial class e metterci l'attributo ma alla fine mi sono dovuto arrendere per il semplice fatto che EntitySet e EntityRef non sono serializzabili a loro volta. A questo punto ho deciso che a me bastava serializzare e quindi anche Xml sarebbe andato bene ma... XmlSerializer non ci riesce, perchè da un errore relativo una circular reference.

Il fatto è che se curiosate nel designer di Visual Studio 2008 scoprirete in fretta una proprietà "Serialization Mode" che può assumere i valori None e Unidirectional. Assegnando Unidirectional la classe generata verrà decorata con gli attributi DataContract e DataMember (e meno male!) e quindi diventerà serializzabile per mezzo del DataContractSerializer o del NetDataContractSerializer. Ecco un esempio di come fare espresso sotto forma di 2 extension methods:

   1: using System;
   2: using System.Collections.Generic;
   3: using System.Linq;
   4: using System.Text;
   5: using System.IO;
   6: using System.Runtime.Serialization;
   7: using System.Xml.Serialization;
   8:  
   9: namespace Elite.Linq2SQL
  10: {
  11:     public static class Extensions
  12:     {
  13:         /// <summary>
  14:         /// Serializes the specified obj.
  15:         /// </summary>
  16:         /// <param name="obj">The obj.</param>
  17:         /// <returns></returns>
  18:         public static string ToXml<T>(this T obj)
  19:         {
  20:             using (MemoryStream stream = new MemoryStream())
  21:             {
  22:                 NetDataContractSerializer serializer = new NetDataContractSerializer();
  23:                 serializer.Serialize(stream, obj);
  24:                 return Encoding.UTF8.GetString(stream.ToArray());
  25:             }
  26:         }
  27:  
  28:         /// <summary>
  29:         /// Deserializes the specified data.
  30:         /// </summary>
  31:         /// <typeparam name="T"></typeparam>
  32:         /// <param name="data">The data.</param>
  33:         /// <returns></returns>
  34:         public static T FromXml<T>(this string xml)
  35:         {
  36:             using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)))
  37:             {
  38:                 NetDataContractSerializer serializer = new NetDataContractSerializer();
  39:                 return (T)serializer.Deserialize(stream);
  40:             }
  41:         }
  42:     }
  43: }

Detto questo può sembrare che bene o male (io propendo per il male...) si sia risolta la questione ma prima di cantare vittoria è opportuno ragionare sul significato di Unidirectional. In breve questo termine sottindente il fatto che la serializzazione comprende esclusivamente l'oggetto radice della gerarchia ed esclude qualunque oggetto che crei un riferimento esterno. Perciò se avete una proprietà collection popolata di oggetti questa non verrà nemmeno presa in considerazione. Il motivo è semplice: così non ci saranno mai circular references.

Quindi tirate le somme si può dire che è meglio togliersi subito dalla testa l'idea di serializzare le entities di Linq To SQL a meno che non vi vogliate impegnare ad implementare ISerializable, che davvero non è la cosa più semplice e immediata che mi venga in mente. Questo, almeno dal mio punto di vista di programmatore ASP.NET significa che le entities non potranno mai essere messe nella ViewState, oppure che se decido inopinatamente di tenerne anche una sola in Session, l'applicazione non potrà mai utilizzare lo State Server di ASP.NET perchè il suo uso implica la serializzazione degli oggetti...

La morale è quindi: occhio a quello che fate!


M'è capitato di sentir parlare dell'entity designer di LINQ come "uno dei tanti inutili designer" di Visual Studio. Non sono un amante dei designer, e quando posso li evito. Ad esempio, per quanto ben fatto sia il designer delle WebForm mi capita di usarlo molto di rado per il semplice fatto che di solito scrivere il codice a mano mi è più rapido.

Ed è proprio questo il punto... il designer deve essere uno strumento che aiuta a risparmiare tempo e non a complicare la vita, perciò mentre un designer come quello per le WebForms ha un utilità relativamente bassa, quello di LINQ è pressochè indispensabile. Per quanto sia possibile scriversi a mano le classi di Linq To SQL chi ci abbia provato si sarà sicuramente reso conto che si tratta di un lavoro improbo e ripetitivo. Non si tratta infatti semplicemente di creare proprietà e metodi, ma anche implementare le interfaccie INotifyPropertyChanged e INotifyPropertyChanging che implicano i dover intervenire sulle proprietà una ad una. Questa implementazione è resa obbligatoria dal fatto che l'object tracking si basa su queste interfacce e senza di esse non sarà in grado di garantire il corretto funzionamento perdendo una delle caratteristiche più importanti di LINQ.

L'uso del designer consente di risparmiare moltissimo tempo e per questo motivo è sicuramente opportuno usarlo.

Technorati Tag: ,

Nei link di oggi di Scott Guthrie c'è ne uno in particolare che ritengo molto utile. Si tratta di un esempio di uso dell'Expression Tree Visualizer, che è stato incluso nell'ultimo aggiornamento degli esempi di CSharp di Visual Studio 2008.

Il tool, che deve essere compilato e installato in Visual Studio (vedere il post originale per le istruzioni), consente di esplorare la struttura di una Expression Tree generata ad esempio in una query LINQ. Si tratta sicuramente di un buon sistema per capire come funzionano questi "strani" oggetti...

Link:


Non sempre si è in grado di scrivere le query LINQ prima di compilare un progetto. Come si può immaginare la possibilità di compilare query composte dinamicamente a runtime è indispensabile. Nel blog di Scott Guthrie è uscito un post che parlava di questo qualche tempo fa, e stamane grazie ad un amico che ne aveva bisogno m'è tornato alla mente. Ecco quindi il link:

Grazie alla libreria (DynamicLibrary.cs) inclusa nei progetti di esempio si possono scrivere cose come la seguente:

   1: Brand brand = (from b in db.Brands
   2:                where b.BrandId == 2
   3:                select b).Single();
   4:  
   5: IQueryable<Car> cars = db.Cars.Where("Brand=@0", brand);
   6:  
   7: foreach (Car car in cars)
   8:     Console.WriteLine(car.Model);

La libreria aggiunge una serie di Extension Methods aggiuntivi che consentono ad esempio di usare una stringa come parametro di una Where...

...Ma non solo... se volete saperne di più, .

Technorati Tag: ,

Dovendo cercare in un array per trovare la stringa più lunga (ma anche la più corta) il codice da scrivere non è molto, ma comunque è abbastanza articolato:

   1: string longest = string.Empty;
   2:  
   3: foreach (string item in stars)
   4:     if (item.Length > longest.Length)
   5:         longest = item;

Quattro righe di codice non sono molte, ma usando LINQ possiamo ottenere il medesimo risultato con una sola riga:

   1: string longest = stars.Aggregate((a, b) => a.Length > b.Length ? a : b);

Il metodo Aggregate durante l'iterazione degli elementi porta con se oltre all'elemento corrente (a) anche quello selezionato dalle precedenti iterazioni (b). Ecco che quindi basta confrontarli e ritornare il più lungo dei due per trovare l'elemento più lungo di tutto l'array. Invertendo il segno > troveremmo il più corto.

Technorati Tag: ,,