<?xml version="1.0" encoding="iso-8859-15"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Ricciolo.NET - Il blog di Cristian "Ricciolo" Civera</title><link>http://blogs.aspitalia.com/ricciolo/</link><description>Ricciolo.NET - Il blog di Cristian "Ricciolo" Civera</description><dc:language>it-it</dc:language><managingEditor>noreply(at)aspitalia.com(Ricciolo.NET - Il blog di Cristian "Ricciolo" Civera)</managingEditor><webMaster>daniele(at)aspitalia.com(Daniele Bochicchio)</webMaster><copyright>1998-2008 ASPItalia.com/Ricciolo.NET - Il blog di Cristian "Ricciolo" Civera</copyright><generator>Generated by feed.ASPItalia.com 'Weyoh' 4.8.703</generator><sy:updatePeriod>hourly</sy:updatePeriod><sy:updateFrequency>1</sy:updateFrequency><sy:updateBase>1998-01-01T12:00+00:00</sy:updateBase><image><title>Ricciolo.NET - Il blog di Cristian "Ricciolo" Civera</title><url>http://blogs.aspitalia.com/blogs.gif</url><link>http://blogs.aspitalia.com/ricciolo/</link></image><item><title>Riutilizzare porzioni di espressioni LINQ</title><link>http://blogs.aspitalia.com/ricciolo/post2306/Riutilizzare-Porzioni-Espressioni-LINQ.aspx</link><pubDate>Fri, 04 Jul 2008 05:31:00 +0100</pubDate><description>&lt;img src='http://blogs.aspitalia.com/services/counter_rss.aspx?PostID=2306' border="0" style="width:1px; height:1px;" /&gt;&lt;p&gt;Se anche voi usate in alcuni progetti &lt;strong&gt;LINQ to SQL&lt;/strong&gt; come &lt;strong&gt;DAL&lt;/strong&gt;, vi troverete un domain model e le classi create tramite il &lt;strong&gt;DBML&lt;/strong&gt;. Questo perché le prime vengono usate nello strato di presentazione e in quello business, mentre le seconde utilizzate all'interno del DAL realizzato con LINQ to SQL.&lt;br /&gt;Di conseguenza ci ritroviamo a dover mappare le due entità in modi più o meno complessi. Poniamo di avere la classe Customer di LINQ to SQL e quella del domain model (per semplificare con mapping 1:1):&lt;/p&gt;&lt;p&gt;&lt;code&gt;public class CustomerL2S&lt;br /&gt;{&lt;br /&gt;   public int ID { get; set; }&lt;br /&gt;   public string Description { get; set; }&lt;br /&gt;}&lt;/p&gt;&lt;p&gt;public class Customer&lt;br /&gt;{&lt;br /&gt;   public int ID { get; set; }&lt;br /&gt;   public string Description { get; set; }&lt;br /&gt;}&lt;/code&gt;&lt;/p&gt;&lt;p&gt;In un ipotetico metodo GetSingle che dato l'ID ti dà l'entità, scriviamo qualcosa del genere:&lt;/p&gt;&lt;p&gt;&lt;code&gt;var customer = from c in customers&lt;br /&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;where c.ID == 1&lt;br /&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;select new Customer&lt;br /&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;{&lt;br /&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;ID = c.ID,&lt;br /&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Description = c.Description&lt;br /&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;};&lt;/code&gt;&lt;/p&gt;&lt;p&gt;Poi magari un metodo di List restituisce tutti i Customer, senza filtrarli e purtroppo ci tocca duplicare l'intera query, compreso tutto il mapping, senza la clausola where. Potremmo essere tentati di fare una funzione, così:&lt;/p&gt;&lt;p&gt;&lt;code&gt;var customer = from c in customers&lt;br /&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;where c.ID == 1&lt;br /&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;select GetCustomer(c);&lt;/code&gt;&lt;/p&gt;&lt;p&gt;Purtroppo questa tecnica non funziona, perché passiamo una funzione managed al motore di LINQ to SQL che non può passarla a SQL Server. Il problema non sta nella funzione, ma in ciò che essa fa. Infatti la soluzione sta nel lavorare sempre a livello di expression tree. Potremmo infatti creare un extension method (solo per comodità nella chiamata) specifico per il Customer che effettua il mapping che ci permetta di riutilizzarlo più volte:&lt;/p&gt;&lt;p&gt;&lt;code&gt;public static class Extentions&lt;br /&gt;{&lt;br /&gt;   public static IQueryable&amp;lt;Customer&amp;gt; SelectToCustomer(this IQueryable&amp;lt;CustomerL2S&amp;gt; source)&lt;br /&gt;   {&lt;br /&gt; &amp;nbsp; &amp;nbsp;   return source.Select(c =&amp;gt; new Customer&lt;br /&gt; &amp;nbsp; &amp;nbsp;   {&lt;br /&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;   ID = c.ID,&lt;br /&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;   Description = c.Description&lt;br /&gt; &amp;nbsp; &amp;nbsp;   });&lt;br /&gt;   }&lt;br /&gt;}&lt;/code&gt;&lt;/p&gt;&lt;p&gt;Nella funzione accettiamo un IQueryable specifico per l'entità CustomerL2S e sfruttando l'extension method select effettuamo il mapping, ma sempre a livello di espressione, consentendola di portarla su SQL Server. L'utilizzo poi è semplice:&lt;/p&gt;&lt;p&gt;&lt;code&gt;var customer = (from c in customers&lt;br /&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;   where c.ID == 1&lt;br /&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;   select c).SelectToCustomer();&lt;/code&gt;&lt;/p&gt;&lt;p&gt;Il doppio select è d'obbligo per via della query syntax, ma non è un problema poiché la query SQL generata è corretta.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Tags:&lt;/strong&gt; &lt;a href="http://tags.aspitalia.com/.NET_Framework/" rel="tag"&gt;.NET Framework&lt;/a&gt;, &lt;a href="http://tags.aspitalia.com/.NET_Framework_3.5/" rel="tag"&gt;.NET Framework 3.5&lt;/a&gt;, &lt;a href="http://tags.aspitalia.com/LINQ/" rel="tag"&gt;LINQ&lt;/a&gt;, &lt;a href="http://tags.aspitalia.com/LINQ_to_SQL/" rel="tag"&gt;LINQ to SQL&lt;/a&gt;&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;a href="http://www.aspitalia.com/"&gt;(C) 2008 ASPItalia.com Network - All rights reserved&lt;/a&gt;&lt;/p&gt;</description><dc:creator>Cristian "Ricciolo" Civera</dc:creator><category>.NET 3.5, .NET Framework, .NET Framework 3.5, LINQ, LINQ to SQL</category><guid isPermaLink="true">http://blogs.aspitalia.com/ricciolo/post2306/Riutilizzare-Porzioni-Espressioni-LINQ.aspx</guid><slash:comments>0</slash:comments><wfw:comments>http://blogs.aspitalia.com/ricciolo/post2306/Riutilizzare-Porzioni-Espressioni-LINQ.aspx#feedback</wfw:comments><wfw:commentRss>http://blogs.aspitalia.com/ricciolo/CommentRSS2306.aspx</wfw:commentRss><trackback:ping>http://blogs.aspitalia.com/services/trackback.aspx?PostID=2306</trackback:ping></item><item><title>LINQ to SQL: Chiamare extension method non implementati</title><link>http://blogs.aspitalia.com/ricciolo/post2302/LINQ-SQL-Chiamare-Extension-Method-Implementati.aspx</link><pubDate>Mon, 30 Jun 2008 18:31:00 +0100</pubDate><description>&lt;img src='http://blogs.aspitalia.com/services/counter_rss.aspx?PostID=2302' border="0" style="width:1px; height:1px;" /&gt;&lt;p&gt;Credo che qualcuno si sia già imbatutto in un problema dovuto ad una query &lt;strong&gt;LINQ to SQL&lt;/strong&gt; simile a questa:&lt;/p&gt;&lt;p&gt;&lt;code&gt;bool MiaFunzione(Customer c)&lt;br /&gt;{&lt;br /&gt;    return true;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;var customer = from c in dc.Customers&lt;br /&gt;               where MiaFunzione(c)&lt;br /&gt;               select c;&lt;/code&gt;&lt;/p&gt;&lt;p&gt;Se lo eseguiamo otterremo un exception perché MiaFunzione è un metodo managed e non può essere valutato tramite una query &lt;strong&gt;SQL&lt;/strong&gt;. L'esempio può sembrare palese, ma in realtà questo problema c'è anche con extesion method come Contains o tutti quelli che accettano un &lt;strong&gt;IEqualityComparer&lt;/strong&gt;, non portabile sul SQL Server.&lt;/p&gt;&lt;p&gt;Poiché quando chiamiamo un extension method il compilatore individua il metodo che come argomento vuole il tipo più vicino alla variabile, quando interroghiamo dc.Customers, la cui proprietà è di tipo &lt;strong&gt;Table&amp;lt;T&amp;gt;&lt;/strong&gt; che a sua volta implementa &lt;strong&gt;IQueryable&amp;lt;T&amp;gt;,&lt;/strong&gt; andiamo a chiamare i metodi contenuti nella classe &lt;strong&gt;System.Linq.Queryable&lt;/strong&gt; i quali lavorano sull'espressione, per poi essere valuta, trasformata in query SQL ed eseguita, all'effettivo consumo dell'enumeratore.&lt;br /&gt;Se però il tipo è &lt;strong&gt;IEnumerable&amp;lt;T&amp;gt;&lt;/strong&gt; andiamo a chiamare i metodi della classe &lt;strong&gt;System.Linq.Enumerable&lt;/strong&gt;, non lavorando più sull'espressione, ma aggiungendo nuovi iteratori che valuteranno T ad ogni ciclo.&lt;/p&gt;&lt;p&gt;Di conseguenza, per risolvere i problema basta effettuare un downcast su IEnumerable&amp;lt;T&amp;gt; o meglio ancora l'extesion method &lt;strong&gt;AsEnumerable&lt;/strong&gt;.&lt;/p&gt;&lt;p&gt;&lt;code&gt;var customer = from c in dc.Customers.AsEnumerable()&lt;br /&gt;               where MiaFunzione(c)&lt;br /&gt;               select c;&lt;/code&gt;&lt;/p&gt;&lt;p&gt;Attenzione però, così facendo l'extension method Where consuma l'intero dc.Customers ottenuto da SQL Server, di conseguenza viene scaricata l'intera tabella dal DB per poi essere filtrata con LINQ to Object. Il alcuni casi potrebbe andare bene, in altri no; basta saperlo.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Tags:&lt;/strong&gt; &lt;a href="http://tags.aspitalia.com/.NET_Framework/" rel="tag"&gt;.NET Framework&lt;/a&gt;, &lt;a href="http://tags.aspitalia.com/.NET_Framework_3.5/" rel="tag"&gt;.NET Framework 3.5&lt;/a&gt;, &lt;a href="http://tags.aspitalia.com/LINQ/" rel="tag"&gt;LINQ&lt;/a&gt;, &lt;a href="http://tags.aspitalia.com/LINQ_to_SQL/" rel="tag"&gt;LINQ to SQL&lt;/a&gt;&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;a href="http://www.aspitalia.com/"&gt;(C) 2008 ASPItalia.com Network - All rights reserved&lt;/a&gt;&lt;/p&gt;</description><dc:creator>Cristian "Ricciolo" Civera</dc:creator><category>.NET 3.5, .NET Framework, .NET Framework 3.5, LINQ, LINQ to SQL</category><guid isPermaLink="true">http://blogs.aspitalia.com/ricciolo/post2302/LINQ-SQL-Chiamare-Extension-Method-Implementati.aspx</guid><slash:comments>0</slash:comments><wfw:comments>http://blogs.aspitalia.com/ricciolo/post2302/LINQ-SQL-Chiamare-Extension-Method-Implementati.aspx#feedback</wfw:comments><wfw:commentRss>http://blogs.aspitalia.com/ricciolo/CommentRSS2302.aspx</wfw:commentRss><trackback:ping>http://blogs.aspitalia.com/services/trackback.aspx?PostID=2302</trackback:ping></item><item><title>Extension method ricorsivo per LINQ</title><link>http://blogs.aspitalia.com/ricciolo/post2298/Extension-Method-Ricorsivo-LINQ.aspx</link><pubDate>Mon, 30 Jun 2008 09:12:00 +0100</pubDate><description>&lt;img src='http://blogs.aspitalia.com/services/counter_rss.aspx?PostID=2298' border="0" style="width:1px; height:1px;" /&gt;&lt;p&gt;Ultimamente sto giocando parecchio con LINQ e trovo incredibile come possa cambiare il modo di scrivere parti di codice: tutto diventa più leggibile e si ha subito l'idea di cosa una query faccia.&lt;/p&gt;&lt;p&gt;Oggi dovevo sfogliare tutte le sezioni di configurazioni e per ognuna chiamare il metodo ProtectSection per criptarla. Siccome ogni gruppo di configurazione ha delle sezioni e a sua volta dei sotto gruppi di configurazione, dovevo fare una funzione da richiamare in modo ricorsivo per ogni gruppo, ma non mi piaceva. La domanda che ormai mi pongo è: si può fare in LINQ? In questo caso no o almeno io non ho trovato un extension method o una combinazione di essi che facesse al caso mio. Perciò ne ho creato uno mio generico, per rendere flat una struttura ad albero:&lt;/p&gt;&lt;p&gt;&lt;code&gt;public static class Extensions&lt;br /&gt;{&lt;br /&gt;  public static IEnumerable&lt;t /&gt; ToFlat&lt;t /&gt;(this IEnumerable&lt;t /&gt; source, Func&amp;lt;T, IEnumerable&amp;lt;T&amp;gt;&lt;t, /&gt;&amp;gt; childPredicate)&lt;br /&gt;  {&lt;br /&gt;    foreach (T t in source)&lt;br /&gt;    {&lt;br /&gt;      yield return t;&lt;/p&gt;&lt;p&gt;      IEnumerable&lt;t /&gt; children = childPredicate(t);&lt;br /&gt;      foreach (T child in ToFlat(children, childPredicate))&lt;br /&gt;        yield return child;&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;}&lt;/code&gt;&lt;/p&gt;&lt;p&gt;In pratica, prende una lista e la sfoglia restituendo ogni elemento della lista stessa. Poi attraverso un predicato ottiene i figli di ogni elemento e per ognuno chiama ricorsivamente la funzione. In questo modo si ottiene un enumeratore piatto che sfoglia tutti gli elementi di una struttura ad al albero.&lt;/p&gt;&lt;p&gt;L'utilizzo poi è banale. Per esempio per sfogliare tutti i controlli di una pagina (il cast serve perché ControlsCollection non implementa IEnumerable&lt;t /&gt;):&lt;/p&gt;&lt;p&gt;&lt;code&gt;var allControls = this.Controls.Cast&lt;control /&gt;().ToFlat(c =&amp;gt; c.Controls)&lt;/code&gt;&lt;/p&gt;&lt;p&gt;Semplice ed efficace, vero?&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Tags:&lt;/strong&gt; &lt;a href="http://tags.aspitalia.com/.NET_Framework/" rel="tag"&gt;.NET Framework&lt;/a&gt;, &lt;a href="http://tags.aspitalia.com/.NET_Framework_3.5/" rel="tag"&gt;.NET Framework 3.5&lt;/a&gt;, &lt;a href="http://tags.aspitalia.com/LINQ/" rel="tag"&gt;LINQ&lt;/a&gt;&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;a href="http://www.aspitalia.com/"&gt;(C) 2008 ASPItalia.com Network - All rights reserved&lt;/a&gt;&lt;/p&gt;</description><dc:creator>Cristian "Ricciolo" Civera</dc:creator><category>.NET 3.5, .NET Framework, .NET Framework 3.5, LINQ</category><guid isPermaLink="true">http://blogs.aspitalia.com/ricciolo/post2298/Extension-Method-Ricorsivo-LINQ.aspx</guid><slash:comments>0</slash:comments><wfw:comments>http://blogs.aspitalia.com/ricciolo/post2298/Extension-Method-Ricorsivo-LINQ.aspx#feedback</wfw:comments><wfw:commentRss>http://blogs.aspitalia.com/ricciolo/CommentRSS2298.aspx</wfw:commentRss><trackback:ping>http://blogs.aspitalia.com/services/trackback.aspx?PostID=2298</trackback:ping></item><item><title>Uso improprio dei generics</title><link>http://blogs.aspitalia.com/ricciolo/post2301/Uso-Improprio-Generics.aspx</link><pubDate>Sat, 28 Jun 2008 17:56:00 +0100</pubDate><description>&lt;img src='http://blogs.aspitalia.com/services/counter_rss.aspx?PostID=2301' border="0" style="width:1px; height:1px;" /&gt;&lt;p&gt;I generics sono tanto belli bellini. Senza di essi non esisterebbe &lt;strong&gt;LINQ&lt;/strong&gt;, gli extension method non avrebbero trovato così ampio spazio e non potremmo scrivere classi generiche utilizzabili per più tipi.&lt;/p&gt;&lt;p&gt;Ci sono alcune pratiche però che mi capitano di vedere e io non ritengo corrette. Per esempio capita di vedere metodi che accettano un tipo generico ed effettuano un cast al loro interno, celandolo al chiamante:&lt;/p&gt;&lt;p&gt;&lt;code&gt;public static T GetValue&amp;lt;T&amp;gt;()&lt;br /&gt;{&lt;br /&gt;    object obj = ....;&lt;br /&gt;    return (T)obj;&lt;br /&gt;}&lt;/code&gt;&lt;/p&gt;&lt;p&gt;L'esempio è banale, ma sufficiente per illustrare il mio dubbio. I generics son nati per tipizzare e migliorare anche in performance (evitano cast e box/unbox). Nel passato si usava un ArrayList e la cosa principalmente brutta era non avere una tipizzazione e si rischiava di cadere in &lt;strong&gt;InvalidCastException&lt;/strong&gt;. Con i generics questo problema è stato risolto. Ciò che non mi piace del codice precedente è che celiamo al chiamante il fatto che io faccio un cast e per chi usa questo metodo sembra tutto sicuro e tipizzato.&lt;br /&gt;In &lt;strong&gt;LINQ to DataSet&lt;/strong&gt; hanno messo l'extesion method &lt;strong&gt;Field&amp;lt;T&amp;gt;&lt;/strong&gt; che data la colonna ti restituisce il valore tipizzato, così:&lt;/p&gt;&lt;p&gt;&lt;code&gt;int c = row.Field&amp;lt;int&amp;gt;(&amp;quot;colonna&amp;quot;)&lt;/code&gt;&lt;/p&gt;&lt;p&gt;Qual'è la differenza rispetto a quest'altro codice?&lt;/p&gt;&lt;p&gt;&lt;code&gt;int c = (int)row[&amp;quot;colonna&amp;quot;]&lt;/code&gt;&lt;/p&gt;&lt;p&gt;Di fatto nessuna. Entrambi sono potenzialmente vittime di un InvalidCastException, solo che il primo codice è stilisticamente più bello da vedere. Non trovate? Ormai avere un cast nel codice è come avere qualcosa di sporco e infatti nella maggior parte dei casi secondo me è così. Con l'extension method generic hanno reso più bello il codice, ma di fatto il problema resta.&lt;br /&gt;E' vero che nella documentazione c'è giustamente scritto che tra le probabili eccezioni c'è tale eccezione, ma a questo punto allora mi domando: perché implementare un metodo del genere?&lt;/p&gt;&lt;p&gt;Viceversa trovo molto bello l'uso dei metodi generic per effettuare downcast. Per esempio:&lt;/p&gt;&lt;p&gt;&lt;code&gt;public static IEnumerable&amp;lt;TSource&amp;gt; AsEnumerable&amp;lt;TSource&amp;gt;(this IEnumerable&amp;lt;TSource&amp;gt; source)&lt;br /&gt;{&lt;br /&gt;    return source;&lt;br /&gt;}&lt;/code&gt;&lt;/p&gt;&lt;p&gt;In questo caso non viene coinvolto nessun cast, cosa che dovrei usare (seppure in modo sicuro) se non avessi questo metodo, ma semplicemente diciamo al compilatore su che tipo riferirsi se poi eventualmente chiamiamo altri metodi.&lt;/p&gt;&lt;p&gt;Ok, ci sono problemi ben più seri nella vita, ma comunque rendo pubblica questa mia riflessione.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Tags:&lt;/strong&gt; &lt;a href="http://tags.aspitalia.com/.NET_Framework/" rel="tag"&gt;.NET Framework&lt;/a&gt;, &lt;a href="http://tags.aspitalia.com/.NET_Framework_3.0/" rel="tag"&gt;.NET Framework 3.0&lt;/a&gt;, &lt;a href="http://tags.aspitalia.com/.NET_Framework_3.5/" rel="tag"&gt;.NET Framework 3.5&lt;/a&gt;, &lt;a href="http://tags.aspitalia.com/LINQ/" rel="tag"&gt;LINQ&lt;/a&gt;&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;a href="http://www.aspitalia.com/"&gt;(C) 2008 ASPItalia.com Network - All rights reserved&lt;/a&gt;&lt;/p&gt;</description><dc:creator>Cristian "Ricciolo" Civera</dc:creator><category>.NET 3.5, .NET Framework, .NET Framework 3.0, .NET Framework 3.5, LINQ</category><guid isPermaLink="true">http://blogs.aspitalia.com/ricciolo/post2301/Uso-Improprio-Generics.aspx</guid><slash:comments>1</slash:comments><wfw:comments>http://blogs.aspitalia.com/ricciolo/post2301/Uso-Improprio-Generics.aspx#feedback</wfw:comments><wfw:commentRss>http://blogs.aspitalia.com/ricciolo/CommentRSS2301.aspx</wfw:commentRss><trackback:ping>http://blogs.aspitalia.com/services/trackback.aspx?PostID=2301</trackback:ping></item><item><title>Le novit&amp;#224; di WPF 3.5 nel service pack 1</title><link>http://blogs.aspitalia.com/ricciolo/post2284/Novita-WPF-3.5-Service-Pack.aspx</link><pubDate>Tue, 13 May 2008 19:56:00 +0100</pubDate><description>&lt;img src='http://blogs.aspitalia.com/services/counter_rss.aspx?PostID=2284' border="0" style="width:1px; height:1px;" /&gt;&lt;p&gt;Come &lt;a href="http://www.aspitalia.com/focuson/1038/Beta-Pubblica-SP1-.NET-Framework-3.5-2008.aspx"&gt;sappiamo&lt;/a&gt; è in corso lo sviluppo del service pack 1 del &lt;strong&gt;.NET Framework 3.5&lt;/strong&gt; e anche WPF non immune da nuove funzionalità.&lt;/p&gt;&lt;p&gt;Cominciamo dai controlli che si arricchiscono dei nuovi &lt;strong&gt;DataGrid&lt;/strong&gt;, &lt;strong&gt;WebBrowser&lt;/strong&gt; e in futuro anche di &lt;strong&gt;Office Ribbon&lt;/strong&gt;. Il primo, fortemente richiesto, supporta modifiche in place transazionali, ordinamento, multi selezione, validazione e la virtualizzazione delle righe e delle colonne come già avviene, per esempio, per la ListBox. Il WebBrowser invece, in alternativa al Frame, permette di accedere al DOM della pagina, avere un maggior controllo del componenti IE e consente di incorporare anche applicazioni in &lt;strong&gt;Silverlight&lt;/strong&gt;.&lt;/p&gt;&lt;p&gt;Ai nuovi controlli si aggiungono piccoli ritocchi:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;supporto StringFormat nelle espressioni di &lt;strong&gt;Binding&lt;/strong&gt;;&lt;/li&gt;&lt;li&gt;template per righe alternate negli &lt;strong&gt;ItemsControl&lt;/strong&gt;;&lt;/li&gt;&lt;li&gt;la virtualizzazione delle righe per gli ItemsControl può ora reciclare (attached property VirtualizationMode) gli elementi non più visibile e permettere lo scrolling e relativa creazione degli elementi solo quando l'utente rilascia il mouse (attached property IsDeferredScrollingEnabled), così da risparmiare memoria. Anche la &lt;strong&gt;TreeView&lt;/strong&gt; supporta ora la virtualizzazione degli elementi. Per maggiori informazioni sull'attuale funzionamento è disponibile &lt;a href="http://www.winfxitalia.com/articoli/presentation-foundation/controlli-elenco-WPF.aspx"&gt;questo articolo&lt;/a&gt;;&lt;/li&gt;&lt;li&gt;nuova interfaccia &lt;strong&gt;IEditableCollectionView&lt;/strong&gt; per intervenire tramite viste sulle sorgenti dati;&lt;/li&gt;&lt;li&gt;supporto al binding con sorgenti Linq To Sql e Linq To Entities migliorando inoltre le performance con &lt;strong&gt;IEnumerable&lt;/strong&gt;;&lt;/li&gt;&lt;li&gt;miglioramenti di performance nel rendering di testo, nella grafica 2D e nella classe &lt;strong&gt;WriteableBitmap&lt;/strong&gt;;&lt;/li&gt;&lt;li&gt;alla proprietà &lt;strong&gt;BitmapEffect&lt;/strong&gt; si affianca Effect che a differenza dell'altra permette di utilizzare effetti come blur e shadow mediante l'accelarazione grafica e sfruttando le capacità di pixel shader delle GPU, rendendolo di fatto di gran lunga più performance rispetto all'elaborazioni bitmap basate su CPU;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;A tutto questo non mancano miglioramenti all'ambiente di sviluppo in &lt;strong&gt;Visual Studio 2008&lt;/strong&gt;, costituiti da un completo supporto agli eventi e agli style, al refactoring e references degli elementi, ad una migliore segnalazione dei problemi in caso di eventuali errori a runtime nel markup, non rilevati in fase di compilazione.&lt;/p&gt;&lt;p&gt;Per ultimo vi sono novità sul fronte client (quindi anche WinForms) e al deployment degli applicativi. E' prevista una nuova modalità &amp;quot;&lt;strong&gt;Client profile&lt;/strong&gt;&amp;quot; che consente di distribuire l'applicativo richiedendo solo un sotto insieme degli assembly contenuti nel framework escludendo quelli che trovano utilità solo in applicazione server, come per esempio la parte di ASP.NET, riducendo il setup a circa 20MB (rispetto a 270MB totali).&lt;br /&gt;Ad esso si unisce un piccolo bootstrapper, compatibile con &lt;strong&gt;ClickOnce&lt;/strong&gt; (interfaccia ora  personalizzabile), che si occupa di installare l'intero .NET Framework 3.5 o se richiesto solo il sotto insieme client e in un secondo momento, se richiesto da un'ulteriore applicazione, di installare il restante Framework.  Anche Visual Studio 2008 supporta questa modalità e presenta degli errori in fase di compilazione nel caso dovessimo usare assembly non presenti nel Framework ridotto.&lt;/p&gt;&lt;p&gt;Non ci sono eclatanti novità a dimostrazione del fatto che già WPF nella sua prima versione era già un ottimo framework, ma devo dire che mi soddisfano. Forse resta l'ambiente di sviluppo ancora un po' indietro e manca ancora di molte funzionalità, ma a piccoli passi forse ce la faremo :-)&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Tags:&lt;/strong&gt; &lt;a href="http://tags.aspitalia.com/.NET_Framework_3.0/" rel="tag"&gt;.NET Framework 3.0&lt;/a&gt;, &lt;a href="http://tags.aspitalia.com/.NET_Framework_3.5/" rel="tag"&gt;.NET Framework 3.5&lt;/a&gt;, &lt;a href="http://tags.aspitalia.com/Visual_Studio/" rel="tag"&gt;Visual Studio&lt;/a&gt;, &lt;a href="http://tags.aspitalia.com/Windows_Presentation_Foundation/" rel="tag"&gt;Windows Presentation Foundation&lt;/a&gt;, &lt;a href="http://tags.aspitalia.com/XAML/" rel="tag"&gt;XAML&lt;/a&gt;, &lt;a href="http://tags.aspitalia.com/.NET_Framework/" rel="tag"&gt;.NET Framework&lt;/a&gt;&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;a href="http://www.aspitalia.com/"&gt;(C) 2008 ASPItalia.com Network - All rights reserved&lt;/a&gt;&lt;/p&gt;</description><dc:creator>Cristian "Ricciolo" Civera</dc:creator><category>.NET 3.5, .NET Framework 3.0, .NET Framework 3.5, Visual Studio, Windows Presentation Foundation, XAML, .NET Framework</category><guid isPermaLink="true">http://blogs.aspitalia.com/ricciolo/post2284/Novita-WPF-3.5-Service-Pack.aspx</guid><slash:comments>0</slash:comments><wfw:comments>http://blogs.aspitalia.com/ricciolo/post2284/Novita-WPF-3.5-Service-Pack.aspx#feedback</wfw:comments><wfw:commentRss>http://blogs.aspitalia.com/ricciolo/CommentRSS2284.aspx</wfw:commentRss><trackback:ping>http://blogs.aspitalia.com/services/trackback.aspx?PostID=2284</trackback:ping></item><item><title>Styles Explorer: decompilatore BAML</title><link>http://blogs.aspitalia.com/ricciolo/post2263/Styles-Explorer-Decompilatore-BAML.aspx</link><pubDate>Fri, 04 Apr 2008 23:57:00 +0100</pubDate><description>&lt;img src='http://blogs.aspitalia.com/services/counter_rss.aspx?PostID=2263' border="0" style="width:1px; height:1px;" /&gt;&lt;p&gt;Vi ricordate quando vi &lt;a href="http://blogs.aspitalia.com/ricciolo/post2124/Come-Fatto-Formato-BAML-WPF.aspx"&gt;parlai&lt;/a&gt; di come viene compilato lo &lt;strong&gt;XAML&lt;/strong&gt; e quale struttura ha? Beh è un po' che avevo più o meno pronta quella classe e mancava qualcosa per usarla a dovere. Portando avanti a singhiozzo il progetto, finalmente posso farvi vedere qualcosa di &lt;strong&gt;Styles Explorer&lt;/strong&gt;.&lt;/p&gt;&lt;p&gt;E' uno strumento che ti permette di aprire qualsiasi DLL, enumerare le risorse &lt;strong&gt;BAML&lt;/strong&gt; che contiene e decompilare (se ce la fa) fornendo l'XML. E' principalmente improntato sui &lt;strong&gt;ResourceDictionary&lt;/strong&gt;, perciò è in grado di fornire un'anteprima di un oggetto o di uno style.&lt;/p&gt;&lt;p&gt;Siccome i tempi cambiano, invece degli screenshot vi metto un bel filmato&lt;/p&gt;&lt;embed pluginspage="http://macromedia.com/go/getflashplayer" src="http://images.video.msn.com/flash/soapbox1_1.swf" width="432" height="364" type="application/x-shockwave-flash" flashvars="c=v&amp;amp;v=184a6290-13ec-4aa3-8c37-51e85d430303&amp;amp;ifs=true&amp;amp;fr=msnvideo&amp;amp;mkt=en-US&amp;amp;brand=" allowscriptaccess="always" allowfullscreen="true" base="http://images.video.msn.com" quality="high" /&gt;&lt;/embed /&gt;&lt;br /&gt;&lt;a title="Styles Explorer" href="http://video.msn.com/video.aspx?vid=184a6290-13ec-4aa3-8c37-51e85d430303" target="_new"&gt;Video: Styles Explorer&lt;/a&gt;&lt;p&gt;Ovviamente il progetto è ancora in corso e va migliorato, ma fino adesso mi son divertito a fare alcune cose carine, come usare più AppDomain per isolare il caricamento degli assembly, o fare una nuova message pump solo per la preview così da evitare problemi con il resto dell'applicazione.&lt;/p&gt;&lt;p&gt;Ah dimenticavo, potete installarlo da &lt;a href="http://ricciolo.lab.aspitalia.com/StylesExplorer/Ricciolo.StylesExplorer.application"&gt;qua&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Tags:&lt;/strong&gt; &lt;a href="http://tags.aspitalia.com/.NET_Framework/" rel="tag"&gt;.NET Framework&lt;/a&gt;, &lt;a href="http://tags.aspitalia.com/.NET_Framework_3.0/" rel="tag"&gt;.NET Framework 3.0&lt;/a&gt;, &lt;a href="http://tags.aspitalia.com/.NET_Framework_3.5/" rel="tag"&gt;.NET Framework 3.5&lt;/a&gt;, &lt;a href="http://tags.aspitalia.com/Windows_Presentation_Foundation/" rel="tag"&gt;Windows Presentation Foundation&lt;/a&gt;, &lt;a href="http://tags.aspitalia.com/XAML/" rel="tag"&gt;XAML&lt;/a&gt;&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;a href="http://www.aspitalia.com/"&gt;(C) 2008 ASPItalia.com Network - All rights reserved&lt;/a&gt;&lt;/p&gt;</description><dc:creator>Cristian "Ricciolo" Civera</dc:creator><category>.NET 3.0, .NET Framework, .NET Framework 3.0, .NET Framework 3.5, Windows Presentation Foundation, XAML</category><guid isPermaLink="true">http://blogs.aspitalia.com/ricciolo/post2263/Styles-Explorer-Decompilatore-BAML.aspx</guid><slash:comments>2</slash:comments><wfw:comments>http://blogs.aspitalia.com/ricciolo/post2263/Styles-Explorer-Decompilatore-BAML.aspx#feedback</wfw:comments><wfw:commentRss>http://blogs.aspitalia.com/ricciolo/CommentRSS2263.aspx</wfw:commentRss><trackback:ping>http://blogs.aspitalia.com/services/trackback.aspx?PostID=2263</trackback:ping></item><item><title>Le evoluzioni del Web che non capisco</title><link>http://blogs.aspitalia.com/ricciolo/post2256/Evoluzioni-Web-Capisco.aspx</link><pubDate>Tue, 18 Mar 2008 17:51:00 +0100</pubDate><description>&lt;img src='http://blogs.aspitalia.com/services/counter_rss.aspx?PostID=2256' border="0" style="width:1px; height:1px;" /&gt;&lt;p&gt;Chi mi conosce sa che non sono un gran simpatizzante di &lt;strong&gt;AJAX&lt;/strong&gt; e riconoscendo che in effetti serve qualcosa di più del buon vecchio HTML, trovo Silverlight decisamente una soluzione migliore. Ma non è di questa moda che voglio parlare, ma bensì di &lt;strong&gt;REST&lt;/strong&gt; e &lt;strong&gt;POX&lt;/strong&gt;.&lt;/p&gt;&lt;p&gt;Con il primo termine si intende il voler sfruttare a pieno le capacità di &lt;strong&gt;HTTP&lt;/strong&gt;, mediante i suoi method, per ampliare l'applicazione web e fornire servizi aggiuntivi usufruibili al di fuori dell'HTML e della semplice navigazione. In pratica, siccome esistono i metodi &lt;strong&gt;GET&lt;/strong&gt;, &lt;strong&gt;POST&lt;/strong&gt;, &lt;strong&gt;PUT&lt;/strong&gt; e &lt;strong&gt;DELETE&lt;/strong&gt; si è pensato di sfruttarli per eseguire le classiche operazioni CRUD, magari aggiugendo dei parametri nell'URI o nel contenuto della richiesta. Tutto questo ovviamente esiste da sempre, ma veniva marginalmente sfruttato e solo ora, e ben venga, siti come Amazon, Google, Live, ecc permettono di interrogare e di usufruire dei loro servizi mediante REST.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;POX&lt;/strong&gt; invece vuol dire Plain Old XML e in pratica vuol dire usare XML semplice senza fronzoli, da utilizzare nelle richieste o risposte REST.&lt;/p&gt;&lt;p&gt;Cosa non mi piace di tutto questo? Il fatto che si sta reinventando la ruota. Per esempio, chi espone operazioni REST si trova a dover fornire della documentazione per spiegare come chiamare le varie operazioni, come dev'essere passato l'XML e spesso in maniera superficiale, limitandosi ad un esempio di XML o ad un esempio di parametro in query string. Beh a tutto questo qualcuno ci aveva già pensato e vedendo che non era sufficiente aveva pensato ai &lt;strong&gt;WebService&lt;/strong&gt;, a &lt;strong&gt;SOAP&lt;/strong&gt;, ai consorzi per renderli i più interoperabili possibili. Per XML esistono gli schema &lt;strong&gt;XSD&lt;/strong&gt; che sono molto più completi, mentre per conoscere quali operazioni espone un servizio c'è &lt;strong&gt;WSDL&lt;/strong&gt; e &lt;strong&gt;WS-Metadata Exchange&lt;/strong&gt;. Senza contare che con framework come &lt;strong&gt;WCF&lt;/strong&gt; basta semplicemente fare un &amp;quot;Add Service reference&amp;quot; e ci si può persino permettere di ignorare questi linguaggi e di esporre della documentazione aggiuntiva.&lt;/p&gt;&lt;p&gt;E' vero che non tutti fanno applicazioni enterprise ed usare WCF/WebService può sembrare un carro armato per uccidere le mosche, ma sono del parere che alcune problematiche sono presenti anche in semplici siti web. Tra questi il già citato, come chiamare un'operazione, ma anche quali errori mi può eventualmente dare e come li gestisco. Poi man mano ci sono altri aspetti, come l'autenticazione, spesso affidata ad un token rilasciato da chi espone il servizio da inserire nella querystring, mentre in &lt;strong&gt;WS-*&lt;/strong&gt; tutto questo è già definito. Sono inoltre definiti come rendere le operazioni sicure, criptate, transazionali, come gestire le policy ed inviare file di grosse dimensioni. Ovviamente se tutto questo non serve basta non abilitarlo e l'XML resta contenuto, senza offenderlo chiamandolo POX :-).&lt;/p&gt;&lt;p&gt;E' per questo che storto un po' il naso e che il diffondersi di questi termini sia più dovuto o ad ignoranza su certe tecnologie (almeno io so il loro nome :-) ) oppure ad una pigrizia nell'affrontarle ed impararle. Detto questo, sicuramente ci sono ambiti in cui una normale richiesta GET basta e avanza; l'importante che vengano valutate anche le altre strade e che non venga coniato qualche nuovo termine o nuova era del web.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Tags:&lt;/strong&gt; &lt;a href="http://tags.aspitalia.com/Silverlight/" rel="tag"&gt;Silverlight&lt;/a&gt;, &lt;a href="http://tags.aspitalia.com/XAML/" rel="tag"&gt;XAML&lt;/a&gt;&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;a href="http://www.aspitalia.com/"&gt;(C) 2008 ASPItalia.com Network - All rights reserved&lt;/a&gt;&lt;/p&gt;</description><dc:creator>Cristian "Ricciolo" Civera</dc:creator><category>.NET 3.5, Silverlight, XAML</category><guid isPermaLink="true">http://blogs.aspitalia.com/ricciolo/post2256/Evoluzioni-Web-Capisco.aspx</guid><slash:comments>11</slash:comments><wfw:comments>http://blogs.aspitalia.com/ricciolo/post2256/Evoluzioni-Web-Capisco.aspx#feedback</wfw:comments><wfw:commentRss>http://blogs.aspitalia.com/ricciolo/CommentRSS2256.aspx</wfw:commentRss><trackback:ping>http://blogs.aspitalia.com/services/trackback.aspx?PostID=2256</trackback:ping></item><item><title>Un'occhiata a Silverlight 2.0</title><link>http://blogs.aspitalia.com/ricciolo/post2248/Unocchiata-Silverlight-2.0.aspx</link><pubDate>Sat, 08 Mar 2008 17:29:00 +0100</pubDate><description>&lt;img src='http://blogs.aspitalia.com/services/counter_rss.aspx?PostID=2248' border="0" style="width:1px; height:1px;" /&gt;&lt;p&gt;Come probabilmente &lt;a href="http://www.aspitalia.com/focuson/1027/Rilasciata-Ufficialmente-Versione-Beta1-Silverlight-2.0.aspx"&gt;saprete&lt;/a&gt; è stata rilasciata la beta &lt;strong&gt;Silverlight 2.0&lt;/strong&gt;.&lt;/p&gt;&lt;p&gt;Ovviamente da fan di &lt;strong&gt;WPF&lt;/strong&gt; non ho resistito dal provarla subito. Sinceramente, delle scorse preview ero rimasto un po' deluso, poiché conoscendo WPF mi rendevo conto di quante cose mancassero diventando così frustrante giocarci. Beh invece con Silverlight 2.0 mi ritengo soddisfatto e entusiasta come un bambino che scarta i regali a Natale :-D&lt;/p&gt;&lt;p&gt;Per prima cosa il setup installa runtime, template per &lt;strong&gt;Visual Studio 2008&lt;/strong&gt; e SDK. Una parte del SDK è rivolta al server e l'altra al client.&lt;/p&gt;&lt;p&gt;Lato server una nuova System.Web.Silverlight.dll contiene i controlli &lt;strong&gt;Silverlight&lt;/strong&gt; e &lt;strong&gt;MediaPlayer&lt;/strong&gt;. Il primo semplicemente crea il markup per istanziare il plugin, include il codice JavaScript e non è più necessario includere script esterni ecc. MediaPlayer è un controllo più evoluto che permette con due click di inserire un player di video con tanto di marcatori e capitoli basandosi su Silverlight. Il tutto completamente skinnabile, con una decina di skin già presenti nel SDK. Molto maschio.&lt;/p&gt;&lt;p&gt;Lato client l'architettura è rimasta invariata e il runtime, di soli 4,3MB, è installato in %ProgramFiles%\Microsoft Silverlight\2.0.30226.2. Rispetto alla alpha abbiamo in più System.ServiceModel (WCF quindi) con &lt;strong&gt;BasicHttpBinding&lt;/strong&gt;, supporto a &lt;strong&gt;REST&lt;/strong&gt; e &lt;strong&gt;JSON&lt;/strong&gt;. L'assembly System.Windows è stato ampliato con altre classi base con niente popo di meno che: StackPanel, Grid, Border, TextBox, ItemsControl (i principali).&lt;/p&gt;&lt;p&gt;Incredibile, c'è la classe &lt;strong&gt;Binding&lt;/strong&gt; con IValueConverter, BindingMode, Source, ma nessun altra tipologia di binding. In molti aspetti Silverlight assomiglia da fuori a WPF, ma dentro l'implementazione è decisamente diversa, tendente al risparmio (non poteva essere diversamente). I controlli sono basati su &lt;strong&gt;DependencyProperty&lt;/strong&gt; (anche Attached Property), ma non è presente nessun meccanismo di triggering o metadati aggiuntivi, mentre gli eventi invece sono quelli normali del CLR; quindi niente Attached Event, niente bubbling o tunneling ed eventi di preview.&lt;/p&gt;&lt;p&gt;I controlli si basano su &lt;strong&gt;Template&lt;/strong&gt; che vengono caricati tramite &lt;strong&gt;Style&lt;/strong&gt; avente come TargetType il tipo del controllo da personalizzare. Gli Style non hanno trigger, quindi nel metodo &lt;strong&gt;ApplyTemplate&lt;/strong&gt; ogni controllo cerca elementi nel template dal nome prefissato (es: RootElement), ne intercettono gli eventi e interagiscono in base a quest'ultimi. Questa tecnica esiste in modo identico anche in WPF, ma si usa raramente preferendo l'uso di trigger in modo da legare il meno possibile il codice al markup. Continuando con il paragone con WPF, niente Command, CollectionView e WeakEvent.&lt;/p&gt;&lt;p&gt;Tutto sommato quindi, le cose che si potevano implementare sono state copiate da WPF e questo non può farmi che piacere :-), ma ovviamente per non esagerare nella dimensione degli assembly è stato sacrificato qualcosa.&lt;/p&gt;&lt;p&gt;Da Visual Studio o Blend 2.5 possiamo creare un progetto Silverlight 2.0 e rispetto a prima, si sviluppa una specie di class library avente già pronti i file App.xaml, che è l'entry point, e un file Page.xaml: lo &lt;strong&gt;UserControl&lt;/strong&gt; principale. Ovviamente hanno il relativo code-behind dove possiamo scrivere in C# 3.0 o VB 9.&lt;br /&gt;Il risultato della compilazione è un file &lt;strong&gt;.xap&lt;/strong&gt;, l'unico file da distribuire, che è un file .zip contenente un file di metadati, i file che abbiamo incluso nel progetto con target Content e la nostra dll compilata. Quest'ultima contiene nelle risorse i file XAML, ma non compilati in &lt;strong&gt;BAML&lt;/strong&gt; (diversamente da WPF). Probabilmente questa scelta è dovuta al fatto che l'ottimizzazione di caricamento del markup è stata ritenuta sacrificabile, mentre la compressione è già ottenuta grazie allo ZIP.&lt;/p&gt;&lt;p&gt;Per ultimo una cosa inaspettata: nel progetto di Visual Studio troveremo referenziati altre dll che verranno poi incluse nel file xap. Queste normalmetne sono: &lt;strong&gt;System.Windows.Controls&lt;/strong&gt; e &lt;strong&gt;System.Windows.Controls.Extended&lt;/strong&gt;. Queste dll, più altre, si trovano normalmente nella cartella del SDK (C:\Program Files\Microsoft SDKs\Silverlight\v2.0\Libraries\Client) e non sono incluse nel setup di Silverlight. Peccato che quest'altre 18 dll contengano: &lt;strong&gt;Ruby&lt;/strong&gt;, &lt;strong&gt;Python&lt;/strong&gt;, &lt;strong&gt;Managed JScript&lt;/strong&gt;, le classi Syndacation RSS/Atom di WCF, &lt;strong&gt;Linq To Xml&lt;/strong&gt;, controlli come Thumb (per il drag&amp;amp;drop), Button, CheckBox, ListBox, RadioButton, Slider, ScrollBar, ScrollViewer, ToolTip, ToggleButton, DataGrid, Calendar, DateTimePicker, GridSplitter, WatermarkedTextBox.&lt;/p&gt;&lt;p&gt;Prima di tutto stupisce che ci siano controlli che WPF non ha e sia Silverlight il primo ad implementarli, ma soprattutto ecco spiegato perché il runtime è piccolo. Infatti tutte le altre dll le mandiamo noi all'utente inglobandole nel file xap. Così l'installazione del plugin è piccola, mentre l'utente navigando su più siti si ritrova a scaricare solo le dll che effettivamente l'applicazione usa, con il rischio ovviamente di scaricare più volte la stessa dll in pacchetti diversi. Furbini vero? :-D&lt;/p&gt;&lt;p&gt;Non l'ho ancora guardato benissimo, ma Silverlight così mi piace decisamente e non ha rivali sul web. Se volete vederlo all'opera potete venire al &lt;a href="http://www.aspitalia.com/eventi/12/Real-Code-Launch-2008-Roma.aspx"&gt;Real Code Launch&lt;/a&gt; che terremo a Roma. Dovete assolutamente venire; chi c'è, c'è, chi non c'è... eh non c'è.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Tags:&lt;/strong&gt; &lt;a href="http://tags.aspitalia.com/.NET_Framework_3.0/" rel="tag"&gt;.NET Framework 3.0&lt;/a&gt;, &lt;a href="http://tags.aspitalia.com/Microsoft_Expression/" rel="tag"&gt;Microsoft Expression&lt;/a&gt;, &lt;a href="http://tags.aspitalia.com/Silverlight/" rel="tag"&gt;Silverlight&lt;/a&gt;, &lt;a href="http://tags.aspitalia.com/Silverlight_-_animazioni/" rel="tag"&gt;Silverlight - animazioni&lt;/a&gt;, &lt;a href="http://tags.aspitalia.com/Silverlight_2.0/" rel="tag"&gt;Silverlight 2.0&lt;/a&gt;, &lt;a href="http://tags.aspitalia.com/Windows_Presentation_Foundation/" rel="tag"&gt;Windows Presentation Foundation&lt;/a&gt;, &lt;a href="http://tags.aspitalia.com/XAML/" rel="tag"&gt;XAML&lt;/a&gt;&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;a href="http://www.aspitalia.com/"&gt;(C) 2008 ASPItalia.com Network - All rights reserved&lt;/a&gt;&lt;/p&gt;</description><dc:creator>Cristian "Ricciolo" Civera</dc:creator><category>.NET 3.0, .NET Framework 3.0, Microsoft Expression, Silverlight, Silverlight - animazioni, Silverlight 2.0, Windows Presentation Foundation, XAML</category><guid isPermaLink="true">http://blogs.aspitalia.com/ricciolo/post2248/Unocchiata-Silverlight-2.0.aspx</guid><slash:comments>4</slash:comments><wfw:comments>http://blogs.aspitalia.com/ricciolo/post2248/Unocchiata-Silverlight-2.0.aspx#feedback</wfw:comments><wfw:commentRss>http://blogs.aspitalia.com/ricciolo/CommentRSS2248.aspx</wfw:commentRss><trackback:ping>http://blogs.aspitalia.com/services/trackback.aspx?PostID=2248</trackback:ping></item><item><title>Ho aperto un nuovo blog</title><link>http://blogs.aspitalia.com/ricciolo/post2227/Aperto-Blog.aspx</link><pubDate>Sat, 16 Feb 2008 18:34:00 +0100</pubDate><description>&lt;img src='http://blogs.aspitalia.com/services/counter_rss.aspx?PostID=2227' border="0" style="width:1px; height:1px;" /&gt;&lt;p&gt;Probabilmente vi domanderete perché abbia aperto un altro blog visto che a mala pena scrivo su questo. Semplice, per scrivere le mie esperienze in inglese. Quindi niente paura, le tematiche sono le stesse e se sfortunatamente leggete già questo blog resterete sempre aggiornati: tutto quello che scriverò in inglese verrà scritto in italiano e forse anche viceversa.&lt;/p&gt;&lt;p&gt;Il blog si trova &lt;a href="http://blogs.windowsclient.net/RiccioloCristian/"&gt;qua&lt;/a&gt;, aggregato sul sito di &lt;a href="http://www.windowsclient.net" target="_blank"&gt;windowsclient.net&lt;/a&gt;.&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;a href="http://www.aspitalia.com/"&gt;(C) 2008 ASPItalia.com Network - All rights reserved&lt;/a&gt;&lt;/p&gt;</description><dc:creator>Cristian "Ricciolo" Civera</dc:creator><category>OT</category><guid isPermaLink="true">http://blogs.aspitalia.com/ricciolo/post2227/Aperto-Blog.aspx</guid><slash:comments>2</slash:comments><wfw:comments>http://blogs.aspitalia.com/ricciolo/post2227/Aperto-Blog.aspx#feedback</wfw:comments><wfw:commentRss>http://blogs.aspitalia.com/ricciolo/CommentRSS2227.aspx</wfw:commentRss><trackback:ping>http://blogs.aspitalia.com/services/trackback.aspx?PostID=2227</trackback:ping></item><item><title>DirectShow e WPF: soluzione finale</title><link>http://blogs.aspitalia.com/ricciolo/post2213/DirectShow-WPF-Soluzione-Finale.aspx</link><pubDate>Mon, 28 Jan 2008 17:20:37 +0100</pubDate><description>&lt;img src='http://blogs.aspitalia.com/services/counter_rss.aspx?PostID=2213' border="0" style="width:1px; height:1px;" /&gt;&lt;p&gt;o quasi... :-) Nel precedente &lt;a href="http://blogs.aspitalia.com/ricciolo/post2210/sorgenti-custom-mediaelement-wpf.aspx" onclick="blankUrl(this.href); return false;"&gt;post&lt;/a&gt; ho parlato delle problematiche e possibili soluzioni per mostrare sorgenti video personalizzate in &lt;strong&gt;WPF&lt;/strong&gt;. Ho accennato ad una possibile terza soluzione e sebbene non perfetta la reputo la migliore.&lt;/p&gt; &lt;p&gt;Partiamo dal risultato. Nella figura sottostante potete ammirare un esemplare maschio homo sapiens sapiens:&lt;/p&gt; &lt;p&gt;&lt;a href="http://blogs.aspitalia.com/img/ricciolo/directshowewpfsoluzionefinale_10201/camera_2.jpg"&gt;&lt;img height="466" alt="camera" src="http://blogs.aspitalia.com/img/ricciolo/directshowewpfsoluzionefinale_10201/camera_thumb.jpg" width="404" border="0" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;L'esempio &amp;#232; ottenuto usando come VisualBrush di un cubo 3D, un mio oggetto:&lt;/p&gt; &lt;p class="codebox"&gt;&lt;code&gt;&amp;lt;ricciolo:WebcamElement Source=&amp;quot;webcam://WebcamElement/Video%20Camera&amp;quot; /&amp;gt;&lt;/code&gt;&lt;/p&gt; &lt;p&gt;Questa classe eredita da una classe base &lt;strong&gt;AdvancedMediaElement&lt;/strong&gt; (eredita dalla standard MediaElement) che offre le funzionalit&amp;#224; base per supportare qualsiasi grafo &lt;strong&gt;DirectShow&lt;/strong&gt;. Nello specifico, per l'intera applicazione uso una libreria Microsoft di nome &lt;a href="http://research.microsoft.com/sn/detours/" onclick="blankUrl(this.href); return false;"&gt;detours&lt;/a&gt; che permette di sovrascrivere le funzioni &lt;strong&gt;Win32&lt;/strong&gt; ed eventualmente chiamare la funzione originale. Per il mio scopo intercetto la chiamata a &lt;strong&gt;CoCreateInstance&lt;/strong&gt;, usata per instanziare gli oggetti &lt;strong&gt;COM&lt;/strong&gt;, e quando il MediaElement carica l'URL coercizzo il valore ad un file fisico vuoto creato al volo nella temp dir. &lt;strong&gt;Windows Media Player&lt;/strong&gt; carica DirectShow, crea il grafo e crea l'AsyncReader standard. Io che sono infame, mediante detours, restituisco un mio oggetto che implementa IAsyncReader e non presenta nessun pin. L'intelligent connect passa il nome del file &lt;strong&gt;IFileSourceFilter::Load&lt;/strong&gt; al mio filtro e poi si ferma, mentre quest'ultimo tramite callback notifica all'AdvancedMediaElement di caricare il grafo. Mediante l'associazione URI/istanza chiamo un metodo virtuale OnGraphLoad(IGraphBuilder graph) nella quale le varie implementazioni (nel mio caso WebcamElement) possono popolare il grafo con i fitri che vogliono lavorando via interop con l'ausilio di librerie tipo &lt;a href="http://directshownet.sourceforge.net/" onclick="blankUrl(this.href); return false;"&gt;DirectShowLib&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;La soluzione &amp;#232; in parte in C++ CLI, in parte in C#, &amp;#232; aperta ad altre implementazioni e non richiede nessuna registrazione di DLL (le detours sono inglobate nel mio assembly) o di protocol handler. L'unica nota dolente &amp;#232; quel finto file vuoto temporaneo che devo creare per costringere WMP ad usare DirectShow; se qualcune conosce quindi un'alternativa sar&amp;#242; ben contento di ascoltarla.&lt;/p&gt; &lt;p&gt;Presto sorgenti e applicazione di test nel lab&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;a href="http://www.aspitalia.com/"&gt;(C) 2008 ASPItalia.com Network - All rights reserved&lt;/a&gt;&lt;/p&gt;</description><dc:creator>Cristian "Ricciolo" Civera</dc:creator><category>.NET 3.0</category><guid isPermaLink="true">http://blogs.aspitalia.com/ricciolo/post2213/DirectShow-WPF-Soluzione-Finale.aspx</guid><slash:comments>0</slash:comments><wfw:comments>http://blogs.aspitalia.com/ricciolo/post2213/DirectShow-WPF-Soluzione-Finale.aspx#feedback</wfw:comments><wfw:commentRss>http://blogs.aspitalia.com/ricciolo/CommentRSS2213.aspx</wfw:commentRss><trackback:ping>http://blogs.aspitalia.com/services/trackback.aspx?PostID=2213</trackback:ping></item><item><title>Sorgenti custom per MediaElement di WPF</title><link>http://blogs.aspitalia.com/ricciolo/post2210/Sorgenti-Custom-MediaElement-WPF.aspx</link><pubDate>Wed, 23 Jan 2008 12:49:59 +0100</pubDate><description>&lt;img src='http://blogs.aspitalia.com/services/counter_rss.aspx?PostID=2210' border="0" style="width:1px; height:1px;" /&gt;&lt;p&gt;L'elemento &lt;strong&gt;MediaElement&lt;/strong&gt; &amp;#232; un gran bell'oggettino :-) Permette di mostrare e ascoltare video e audio, il tutto perfettamente integrato con WPF permettendoci di ridimensionarlo come ci pare, usarlo come brush, trasformarlo, applicare trasparenze, ecc...&lt;/p&gt; &lt;p&gt;L'unico problema &amp;#232; che al di l&amp;#224; di file su disco o uri http, non si pu&amp;#242; andare. Per esempio pu&amp;#242; essere utile usare come sorgente la webcam, un tuner TV o una fonte analogica esterna. Per ottenere ci&amp;#242; ci sono vari modi:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Usare l'elemento &lt;strong&gt;HwndSource&lt;/strong&gt; cos&amp;#236; da avere una finestra Win32. Tramite la propriet&amp;#224; Handle abbiamo il suo puntatore e possiamo quindi usare &lt;strong&gt;DirectShow&lt;/strong&gt; effettuando il rendering puntando la finestra con l'interfaccia &lt;a href="http://msdn2.microsoft.com/en-us/library/ms786984.aspx" onclick="blankUrl(this.href); return false;"&gt;IVideoWindow&lt;/a&gt;. Se vi interessa &amp;#232; disponibile &lt;a href="http://directshownet.sourceforge.net/" onclick="blankUrl(this.href); return false;"&gt;questo progetto&lt;/a&gt; pieno di classi interop per usare DirectShow in .NET. &lt;br /&gt;Questo approccio ha dei limiti dovuti al fatto che HwndSource &amp;#232; s&amp;#236; un elemento WPF, ma poich&amp;#233; contiene al suo interno una nuova finestra Win32 non permette di effettuare trasformazioni, trasparenze, ecc.&lt;/li&gt; &lt;li&gt;Costruire un protocol handler per un proprio schema (esempio webcam://qualcosa) che faccia uso di un source filter personalizzato per DirectShow. Questo &amp;#232; possibile perch&amp;#233; MediaElement utilizza al suo interno &lt;strong&gt;Windows Media Player&lt;/strong&gt; che a sua volta si basa su &lt;strong&gt;Windows Media Foundation&lt;/strong&gt; che a sua volta usa (se necessario) DirectShow.&lt;/li&gt; &lt;/ul&gt; &lt;p&gt;Ho provato entrambi le modalit&amp;#224; e ovviamente la seconda &amp;#232; la migliore (esiste una terza che sto ancora sperimentando). Nella seconda ho scritto in C++ un source filter che implementa &lt;a href="http://msdn2.microsoft.com/en-us/library/ms785718.aspx" onclick="blankUrl(this.href); return false;"&gt;IFileSourceFilter&lt;/a&gt;, cos&amp;#236; da essere da essere chiamato per caricare il mio schema custom. Non entro troppo nei dettagli, ma &amp;#232; compito di WMP caricare il mio filtro e, una volta aggiunto al grafo DirectShow, renderizzare il pin video in uscita sfruttando l'&lt;a href="http://msdn2.microsoft.com/en-us/library/ms786503(vs.85).aspx" onclick="blankUrl(this.href); return false;"&gt;Intelligent Connect&lt;/a&gt;. Questo sistema in pratica si mette a guardare i pin del filtro sorgente e prova le possibili combinazioni tra filtri di decodifica e di rendering fino a quando non riesce a mostrare il video e/o ad emettere il suono. In WPF il filtro sorgente quindi dipende dal protocol handler, mentre il rendering video viene effettuato mediante &lt;a href="http://msdn2.microsoft.com/en-us/library/ms694916(vs.85).aspx" onclick="blankUrl(this.href); return false;"&gt;Enhanced Video Renderer&lt;/a&gt;: un filtro nuovo e pi&amp;#249; evoluto che permette l'integrazione in WPF.&lt;/p&gt; &lt;p&gt;Nella mia prova ho usato il tipico filtro Ball presente nel SDK, costituito da un pin che restituisce uno stream video che mostra una palla rimbalzare. Una volta pronto il filtro, va poi registrato sia come dll, sia mappando lo schema custom al filtro. Possiamo poi usarlo sia in WMP che in GraphEdit (un tool per testare i filtri). Ecco uno screenshot:&lt;/p&gt; &lt;p&gt;&lt;a href="http://blogs.aspitalia.com/img/ricciolo/sorgenticustompermediaelementdiwpf_9079/ball1.png"&gt;&lt;img height="347" alt="ball1" src="http://blogs.aspitalia.com/img/ricciolo/sorgenticustompermediaelementdiwpf_9079/ball1_thumb.png" width="400" border="0" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;A questo punto possiamo usare il filtro anche in WPF:&lt;/p&gt; &lt;p class="codebox"&gt;&lt;code&gt;&amp;lt;MediaElement Source=&amp;quot;ball://test&amp;quot; /&amp;gt;&lt;/code&gt;&lt;/p&gt; &lt;p&gt;E questo &amp;#232; il risultato che si ottiene applicandoci il tipico effetto riflesso, per far vedere che possiamo trattare il video come vogliamo:&lt;/p&gt; &lt;p&gt;&lt;a href="http://blogs.aspitalia.com/img/ricciolo/sorgenticustompermediaelementdiwpf_9079/ball2.png"&gt;&lt;img height="360" alt="ball2" src="http://blogs.aspitalia.com/img/ricciolo/sorgenticustompermediaelementdiwpf_9079/ball2_thumb.png" width="250" border="0" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;Quindi in teoria possiamo fare un pin che prenda lo stream da un grafo interno oppure possiamo fare un filtro senza pin, ma che sul metodo Load inserisce nel grafo un nuovo filtro sorgente (webcam, tuner ecc). Ci pensa poi l'intelligent connect ad ignorare il nostro filtro custom, proseguendo sull'altro da noi creato. Questa variante &amp;#232; stilisticamente meno carina, ma pi&amp;#249; semplice.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Tags:&lt;/strong&gt; &lt;a href="http://tags.aspitalia.com/.NET_Framework/" rel="tag"&gt;.NET Framework&lt;/a&gt;, &lt;a href="http://tags.aspitalia.com/.NET_Framework_3.0/" rel="tag"&gt;.NET Framework 3.0&lt;/a&gt;, &lt;a href="http://tags.aspitalia.com/.NET_Framework_3.5/" rel="tag"&gt;.NET Framework 3.5&lt;/a&gt;, &lt;a href="http://tags.aspitalia.com/Windows_Presentation_Foundation/" rel="tag"&gt;Windows Presentation Foundation&lt;/a&gt;, &lt;a href="http://tags.aspitalia.com/XAML/" rel="tag"&gt;XAML&lt;/a&gt;&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;a href="http://www.aspitalia.com/"&gt;(C) 2008 ASPItalia.com Network - All rights reserved&lt;/a&gt;&lt;/p&gt;</description><dc:creator>Cristian "Ricciolo" Civera</dc:creator><category>.NET 3.0, .NET Framework, .NET Framework 3.0, .NET Framework 3.5, Windows Presentation Foundation, XAML</category><guid isPermaLink="true">http://blogs.aspitalia.com/ricciolo/post2210/Sorgenti-Custom-MediaElement-WPF.aspx</guid><slash:comments>1</slash:comments><wfw:comments>http://blogs.aspitalia.com/ricciolo/post2210/Sorgenti-Custom-MediaElement-WPF.aspx#feedback</wfw:comments><wfw:commentRss>http://blogs.aspitalia.com/ricciolo/CommentRSS2210.aspx</wfw:commentRss><trackback:ping>http://blogs.aspitalia.com/services/trackback.aspx?PostID=2210</trackback:ping></item><item><title>Anonymous type di C# 3.0</title><link>http://blogs.aspitalia.com/ricciolo/post2197/Anonymous-Type-CSharp-3.0.aspx</link><pubDate>Fri, 04 Jan 2008 14:21:18 +0100</pubDate><description>&lt;img src='http://blogs.aspitalia.com/services/counter_rss.aspx?PostID=2197' border="0" style="width:1px; height:1px;" /&gt;&lt;p&gt;Giocando con &lt;strong&gt;LINQ&lt;/strong&gt; avrete senz'altro usato gli anonymous type: quei tipi creati al volo per contenere varie informazioni. Poniamo questo semplice esempio:&lt;/p&gt; &lt;p class="colorato"&gt;&lt;code&gt;var v = new {Language = &amp;quot;IT&amp;quot;, Age=30};&lt;/code&gt;&lt;/p&gt; &lt;p&gt;Prima di tutto, v &amp;#232; visibile solo all'interno dello stack in cui l'abbiamo dichiarato. Quindi all'interno di una funzione o metodo, ma mai a livello di classe. Possiamo anche ritornarlo come valore da una funzione, ma potremmo limitarci a ritornare un tipo object generico e non potremmo fare riferimento al nome del tipo, facendo cast o quant'altro (se non via reflection, bleah bleah). Quindi ques'ultima opzione &amp;#232; fortemente sconsigliata.&lt;/p&gt; &lt;p&gt;Quando compiliamo, viene automaticamente generata una classe internal sealed dal nome f__AnonymousType[numero] sul namespace root. La classe eredita da Object definisce n propriet&amp;#224; e n campi per memorizzare i valori e dispone di un costruttore che accetta come parametri i valori da impostare sulle propriet&amp;#224;. Non c'&amp;#232; modo di cambiarne visibilit&amp;#224; ai tipi o ai membri, ne di rendere in sola lettura le propriet&amp;#224;. Questa classe ha la particolarit&amp;#224; di essere generica, nel senso che i tipi string e int delle propriet&amp;#224; Language e Age del nostro esempio, sono generici. Questo per evitare di creare copie della medesima classe. Quindi se utiliziamo nel medesimo assembly un anonymous type simile:&lt;/p&gt; &lt;p class="colorato"&gt;&lt;code&gt;var v = new {Language = 1, Age=3d};&lt;/code&gt;&lt;/p&gt; &lt;p&gt;verr&amp;#224; utilizzata la medesima classe autogenerata, ma con generics argument diversi: int e double.&lt;/p&gt; &lt;p&gt;Tale classe inoltre sovrascrive ToString per mostrare facilmente il contenuto, Equals e GetHashCode cos&amp;#236; da rendere comparabile il tipo quando viene utilizzato, per esempio da LINQ To Objects:&lt;/p&gt; &lt;p class="colorato"&gt;&lt;code&gt;[DebuggerHidden] &lt;br /&gt;public override string ToString() &lt;br /&gt;{ &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; StringBuilder builder = new StringBuilder(); &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; builder.Append(&amp;quot;{ Language = &amp;quot;); &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; builder.Append(this.&amp;lt;Language&amp;gt;i__Field); &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; builder.Append(&amp;quot;, Age = &amp;quot;); &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; builder.Append(this.&amp;lt;Age&amp;gt;i__Field); &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; builder.Append(&amp;quot; }&amp;quot;); &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; return builder.ToString(); &lt;br /&gt;} &lt;br /&gt; &lt;br /&gt;[DebuggerHidden] &lt;br /&gt;public override int GetHashCode() &lt;br /&gt;{ &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; int num = 0x5b485bf4; // Numero casuale &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; num = (-1521134295 * num) + EqualityComparer&amp;lt;&amp;lt;Language&amp;gt;j__TPar&amp;gt;.Default.GetHashCode(this.&amp;lt;Language&amp;gt;i__Field); &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; return ((-1521134295 * num) + EqualityComparer&amp;lt;&amp;lt;Age&amp;gt;j__TPar&amp;gt;.Default.GetHashCode(this.&amp;lt;Age&amp;gt;i__Field)); &lt;br /&gt;} &lt;br /&gt; &lt;br /&gt;[DebuggerHidden] &lt;br /&gt;public override bool Equals(object value) &lt;br /&gt;{ &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; var type = value as &amp;lt;&amp;gt;f__AnonymousType0&amp;lt;&amp;lt;Language&amp;gt;j__TPar, &amp;lt;Age&amp;gt;j__TPar&amp;gt;; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; return (((type != null) &amp;amp;&amp;amp; EqualityComparer&amp;lt;&amp;lt;Language&amp;gt;j__TPar&amp;gt;.Default.Equals(this.&amp;lt;Language&amp;gt;i__Field, type.&amp;lt;Language&amp;gt;i__Field)) &amp;amp;&amp;amp; EqualityComparer&amp;lt;&amp;lt;Age&amp;gt;j__TPar&amp;gt;.Default.Equals(this.&amp;lt;Age&amp;gt;i__Field, type.&amp;lt;Age&amp;gt;i__Field)); &lt;br /&gt;}&lt;/code&gt;&lt;/p&gt; &lt;p&gt;Sono interessanti l'uso di &lt;strong&gt;DebuggerHidden&lt;/strong&gt; per evitare di far vedere dal debugger tali metodi e l'uso di &lt;strong&gt;EqualityComparer.Default&lt;/strong&gt; per ottenere l'hashcode o comparare i tipi primitivi utilizzati. EqualityComparer.Default restituisce un &lt;strong&gt;IEqualityComparer&amp;lt;T&amp;gt;&lt;/strong&gt; (fondamentale in LINQ) a seconda che il tipo implementi IEquatable&amp;lt;T&amp;gt;, sia nullabile o come ultima spiaggia, sovrascriva Equals e GetHashCode. Per comparare le stringhe (utile sempre in LINQ) abbiamo a disposizione la classe &lt;strong&gt;StringComparer&lt;/strong&gt; che permette diversi modi di comparazione delle stringhe: CurrentCulture, CurrentCultureIgnoreCase, InvariantCulture, InvariantCultureIgnoreCase, Ordinal, OrdinalIgnoreCase.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Tags:&lt;/strong&gt; &lt;a href="http://tags.aspitalia.com/.NET_Framework/" rel="tag"&gt;.NET Framework&lt;/a&gt;, &lt;a href="http://tags.aspitalia.com/.NET_Framework_3.5/" rel="tag"&gt;.NET Framework 3.5&lt;/a&gt;, &lt;a href="http://tags.aspitalia.com/LINQ/" rel="tag"&gt;LINQ&lt;/a&gt;&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;a href="http://www.aspitalia.com/"&gt;(C) 2008 ASPItalia.com Network - All rights reserved&lt;/a&gt;&lt;/p&gt;</description><dc:creator>Cristian "Ricciolo" Civera</dc:creator><category>.NET 3.0, .NET Framework, .NET Framework 3.5, LINQ</category><guid isPermaLink="true">http://blogs.aspitalia.com/ricciolo/post2197/Anonymous-Type-CSharp-3.0.aspx</guid><slash:comments>0</slash:comments><wfw:comments>http://blogs.aspitalia.com/ricciolo/post2197/Anonymous-Type-CSharp-3.0.aspx#feedback</wfw:comments><wfw:commentRss>http://blogs.aspitalia.com/ricciolo/CommentRSS2197.aspx</wfw:commentRss><trackback:ping>http://blogs.aspitalia.com/services/trackback.aspx?PostID=2197</trackback:ping></item><item><title>Habemus CardSpace!</title><link>http://blogs.aspitalia.com/ricciolo/post2198/Habemus-CardSpace.aspx</link><pubDate>Thu, 03 Jan 2008 14:51:00 +0100</pubDate><description>&lt;img src='http://blogs.aspitalia.com/services/counter_rss.aspx?PostID=2198' border="0" style="width:1px; height:1px;" /&gt;&lt;p&gt;E' un po' che io e &lt;a onclick="function anonymous()
{
function anonymous()
{
blankUrl(this.href); return false;
}
}" href="http://blogs.aspitalia.com/daniele"&gt;Daniele&lt;/a&gt; ci stiamo lavorando (circa due mesi), ma finalmente abbiamo implementato &lt;strong&gt;CardSpace&lt;/strong&gt; nella nostra community. Questo significa che da ora in poi potete fare login utilizzando le card self-issued. Una guida su come funziona l'ambaradam la trovate &lt;a onclick="function anonymous()
{
function anonymous()
{
blankUrl(this.href); return false;
}
}" href="https://secure.aspitalia.com/profile/infocard.aspx"&gt;qua&lt;/a&gt; e se avete già a disposizione una card e non siente registratati, allora create un profilo &lt;a onclick="function anonymous()
{
function anonymous()
{
blankUrl(this.href); return false;
}
}" href="https://secure.aspitalia.com/profile/policy.aspx"&gt;qua&lt;/a&gt;, oppure associate la card ad un account pre esiste, dopo aver fatto il login, andando &lt;a onclick="function anonymous()
{
function anonymous()
{
blankUrl(this.href); return false;
}
}" href="https://secure.aspitalia.com/profile/setcard.aspx"&gt;qua&lt;/a&gt;. In generale la vostra card personale è utilizzabile in tutti i portali dove compare questo logo standard:&lt;/p&gt;&lt;p&gt;&lt;img alt=" " hspace="0" src="http://blogs.aspitalia.com/img/Ricciolo/CardSpace.png" border="0" /&gt; &lt;/p&gt;&lt;p&gt;Ovviamente la domanda è: perché supportare l'identity metasystem?&lt;/p&gt;&lt;p&gt;Risposta:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;perché adeguarsi ad un sistema standard ed interoperabile ci permette di accogliere nuovi utenti molto più facilmente. Basta selezionare la card utilizzata già su altri portali e le informazioni sono già disponibili; &lt;/li&gt;&lt;li&gt;perché non serve più ricordarsi di password, utenti ed email; &lt;/li&gt;&lt;li&gt;perché un'unica interfaccia di selezione basata su comunicazioni sicure, è sicuramente meglio dei mille sistemi inventati da ogni programmatore del mondo, abbattendo inoltre così, fenomeni come phishing; &lt;/li&gt;&lt;li&gt;perché questo sistema di autenticazione è utilizzabile anche al di fuori dal web: applicazioni windows, webservice ecc. &lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Non temete, implementare identity metasystem nei vostri portali è facile e fattibile. L'unica difficoltà è il certificato per il canale SSL, ma dal .NET Framework 3.5 non è più obbligatorio se il nostro sito non è una banca :-) La difficoltà che abbiamo incontrato è stata nel cercare di implementare un &lt;strong&gt;STS&lt;/strong&gt; (Security Token Server) per rilasciare delle nostre card marcate ASPItalia.com/WinFXItalia.com, da utilizzare nelle nostre community. Beh dunque, fare un STS non è affatto semplice e il materiale a disposizione non è completo. Parlando comunque con &lt;a onclick="function anonymous()
{
function anonymous()
{
blankUrl(this.href); return false;
}
}" href="http://blogs.msdn.com/vbertocci/"&gt;Vittorio Bertocci&lt;/a&gt;, che lavora in Microsoft e si sta dando parecchio da fare per diffondere l'adozione dell'identity metasystem, abbiamo maturato l'idea che fare da STS è troppo per noi. STS che rilascia managed card deve essere un ente, una banca, uno stato. Per la nostra community bastano le semplici self-issued card. Maggiori dettagli tecnici sull'argomento li trovate &lt;a onclick="function anonymous()
{
function anonymous()
{
blankUrl(this.href); return false;
}
}" href="http://www.winfxitalia.com/articoli/winfx/gestione-identita-digitali-windows-cardspace.aspx"&gt;qua&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Tags:&lt;/strong&gt; &lt;a href="http://tags.aspitalia.com/ASPItalia.com/" rel="tag"&gt;ASPItalia.com&lt;/a&gt;&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;a href="http://www.aspitalia.com/"&gt;(C) 2008 ASPItalia.com Network - All rights reserved&lt;/a&gt;&lt;/p&gt;</description><dc:creator>Cristian "Ricciolo" Civera</dc:creator><category>.NET 3.0, ASPItalia.com</category><guid isPermaLink="true">http://blogs.aspitalia.com/ricciolo/post2198/Habemus-CardSpace.aspx</guid><slash:comments>4</slash:comments><wfw:comments>http://blogs.aspitalia.com/ricciolo/post2198/Habemus-CardSpace.aspx#feedback</wfw:comments><wfw:commentRss>http://blogs.aspitalia.com/ricciolo/CommentRSS2198.aspx</wfw:commentRss><trackback:ping>http://blogs.aspitalia.com/services/trackback.aspx?PostID=2198</trackback:ping></item><item><title>WPF: attenzione ai template predefiniti</title><link>http://blogs.aspitalia.com/ricciolo/post2196/WPF-Attenzione-Template-Predefiniti.aspx</link><pubDate>Wed, 02 Jan 2008 13:48:16 +0100</pubDate><description>&lt;img src='http://blogs.aspitalia.com/services/counter_rss.aspx?PostID=2196' border="0" style="width:1px; height:1px;" /&gt;&lt;p&gt;Certo, si pu&amp;#242; dormire lo stesso anche non sapendolo, ma sul nostro &lt;a href="http://forum.aspitalia.com/forum/29/.net-framework-3.0.aspx" onclick="blankUrl(this.href); return false;"&gt;forum&lt;/a&gt; &amp;#232; stata posta un'interessante domanda relativa ai Content di &lt;strong&gt;WPF&lt;/strong&gt;. Purtroppo la comodit&amp;#224; di certi elementi presenti ci fa ignorare il dietro le quinte e a volte ci porta a risultati inaspettati. E' il caso delle classi &lt;strong&gt;ContentControl&lt;/strong&gt; e &lt;strong&gt;HeaderedContentControl&lt;/strong&gt; che dispongono delle propriet&amp;#224; &lt;strong&gt;Header&lt;/strong&gt; e &lt;strong&gt;Content&lt;/strong&gt; di tipo Object e ci consentono di fare questo:&lt;/p&gt; &lt;p class="colorato"&gt;&lt;code&gt;&amp;lt;Button&amp;gt;Ciao!&amp;lt;/Button&amp;gt;&lt;/code&gt;&lt;/p&gt; &lt;p&gt;Innanzitutto tramite l'interfaccia IAddChild la stringa &amp;quot;Ciao!&amp;quot; viene impostata sulla propriet&amp;#224; Content ed equivale quindi a scrivere:&lt;/p&gt; &lt;p class="colorato"&gt;&lt;code&gt;&amp;lt;Button&amp;gt; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &amp;lt;Button.Content&amp;gt;Ciao!&amp;lt;/Button.Content&amp;gt; &lt;br /&gt;&amp;lt;/Button&amp;gt;&lt;/code&gt;&lt;/p&gt; &lt;p&gt;I vari skin applicati a Button o controlli simili, utilizzano l'oggetto &lt;strong&gt;ContentPresenter&lt;/strong&gt; per includere il contenuto nel layout. Quest'oggetto applica dei template predefiniti a seconda del tipo presente in Content:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Se &amp;#232; una stringa e &lt;strong&gt;RecognizesAccessKey&lt;/strong&gt; &amp;#232; a true, utilizza un template che crea un &lt;strong&gt;AccessText&lt;/strong&gt; e con Text valorizzato con il Content stesso; altrimenti utilizza un normale TextBlock con Text valorizzato con il Content stesso;&lt;/li&gt; &lt;li&gt;Se &amp;#232; un &lt;strong&gt;UIElement&lt;/strong&gt;, inserisce l'elemento stesso direttamente come figlio;&lt;/li&gt; &lt;li&gt;Se &amp;#232; un &lt;strong&gt;XmlNode&lt;/strong&gt;, utilizza un TextBlock con Binding XPath = &amp;quot;.&amp;quot;&lt;/li&gt; &lt;li&gt;Per gli altri restanti tipi, utilizza un TextBlock cercando di convertire prima con un &lt;strong&gt;TypeConverter&lt;/strong&gt; e poi con un ToString il tipo impostato come Content.&lt;/li&gt; &lt;/ul&gt; &lt;p&gt;Detto questo, quali possono essere i risultati inattesi? Prendiamo questo esempio:&lt;/p&gt; &lt;p class="colorato"&gt;&lt;code&gt;&amp;lt;Menu&amp;gt; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &amp;lt;MenuItem Header=&amp;quot;_One&amp;quot; /&amp;gt; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &amp;lt;MenuItem Header=&amp;quot;_Two&amp;quot; /&amp;gt; &lt;br /&gt;&amp;lt;/MenuItem&amp;gt;&lt;/code&gt;&lt;/p&gt; &lt;p&gt;L'uso degli underscore &amp;#232; riconosciuto da AccessText (il ContentPresenter del MenuItem ha RecognizesAccessKey a true) e permette l'utilizzo dello shorcut effettuando la sottolineatura della lettera che lo segue. Se usiamo per&amp;#242; il Binding XML, per esempio, gli underscore non vengono pi&amp;#249; rinosciuti:&lt;/p&gt; &lt;p class="colorato"&gt;&lt;code&gt;&amp;lt;MenuItem Header=&amp;quot;{Binding XPath=/item/@text}&amp;quot; /&amp;gt;&lt;/code&gt;&lt;/p&gt; &lt;p&gt;Questo perch&amp;#233; non viene pi&amp;#249; usato il template predefinito riservato alle stringhe. Per ovviare a questo problema, occorre creare in modo esplicito l'oggetto AccessText:&lt;/p&gt; &lt;p class="colorato"&gt;&lt;code&gt;&amp;lt;MenuItem&amp;gt; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &amp;lt;MenuItem.Header&amp;gt; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;AccessText Text=&amp;quot;{Binding XPath=/item/@text}&amp;quot; /&amp;gt; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &amp;lt;/MenuItem.Header&amp;gt; &lt;br /&gt;&amp;lt;/MenuItem&amp;gt;&lt;/code&gt;&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;a href="http://www.aspitalia.com/"&gt;(C) 2008 ASPItalia.com Network - All rights reserved&lt;/a&gt;&lt;/p&gt;</description><dc:creator>Cristian "Ricciolo" Civera</dc:creator><category>.NET 3.0</category><guid isPermaLink="true">http://blogs.aspitalia.com/ricciolo/post2196/WPF-Attenzione-Template-Predefiniti.aspx</guid><slash:comments>0</slash:comments><wfw:comments>http://blogs.aspitalia.com/ricciolo/post2196/WPF-Attenzione-Template-Predefiniti.aspx#feedback</wfw:comments><wfw:commentRss>http://blogs.aspitalia.com/ricciolo/CommentRSS2196.aspx</wfw:commentRss><trackback:ping>http://blogs.aspitalia.com/services/trackback.aspx?PostID=2196</trackback:ping></item><item><title>Curiosit&amp;#224; sui Thread</title><link>http://blogs.aspitalia.com/ricciolo/post2187/Curiosita-Thread.aspx</link><pubDate>Sun, 16 Dec 2007 23:45:00 +0100</pubDate><description>&lt;img src='http://blogs.aspitalia.com/services/counter_rss.aspx?PostID=2187' border="0" style="width:1px; height:1px;" /&gt;&lt;p&gt;In questi giorni grazie ad un esigenza di &lt;a onclick="function anonymous()
{
function anonymous()
{
function anonymous()
{
blankUrl(this.href); return false;
}
}
}" href="http://blogs.devleap.com/rob/"&gt;Rob&lt;/a&gt; e &lt;a onclick="function anonymous()
{
function anonymous()
{
function anonymous()
{
blankUrl(this.href); return false;
}
}
}" href="http://blogs.devleap.com/paolo/"&gt;Paolo&lt;/a&gt;, ho voluto approfondire un aspetto di cui ero già a conoscienza, ma del quale non avevo mai fatto test. &lt;br /&gt;Come sapete, un campo dichiarato in una classe può teoricamente subire contemporaneamente l'accesso da più &lt;strong&gt;thread&lt;/strong&gt; e spesso per rendere la classe thread-safe si ricorrono a tecniche di sincronizzazione per evitare che più thread cambino contemporanemante il campo. Non è detto infatti che una singola istruzione di assegnazione sia una singola istruzione di CPU e questo può portare ad inaspettati risultati. Questo problema si fa inoltre più frequente se si dichiara static (o shared in VB) il campo, condividendo il valore del membro per l'intero AppDomain.&lt;/p&gt;&lt;p&gt;A volte però, si vuole rendere l'istanza del campo accessible da chiunque purché dal medesimo thread, togliendo quindi il problema dell'accesso concorrente. L'attributo &lt;strong&gt;ThreadStatic&lt;/strong&gt; permette di marcare un campo e di avere questo comportamento:&lt;/p&gt;&lt;p&gt;&lt;code&gt;[ThreadStatic] &lt;br /&gt;private static object threadState;&lt;/code&gt;&lt;/p&gt;&lt;p&gt;Questa tecnica viene sfruttata per esempio dall'oggetto &lt;strong&gt;Transaction&lt;/strong&gt; (System.Transactions) per mantenere l'oggetto rappresentante la transazione corrente cosicchè qualsiasi sotto chiamata possa accedere alla transazione corrente semplicemente chiamando Transaction.Current, il tutto isolato per thread (la transazione infatti non è visibile in altri thread, ma ne viene creata un'altra). Lo stesso comportamento, seppure meno comodo, si può ottenere usando &lt;strong&gt;Thread.AllocateNamedDataSlot&lt;/strong&gt;, Thread.SetData e Thread.GetData che permettono di allocare per nome uno spazio, di impostarlo e di leggerlo, dove inserire un riferimento ad un oggetto.&lt;/p&gt;&lt;p&gt;La problematica di questo approccio è che nel caso in cui da un thread ne avviamo un altro e si vuole portare con se questi valori &amp;quot;speciali&amp;quot;, occorre passarseli tramite argomenti o classi d'appoggio per poi essere copiati sul nuovo thread. Inoltre nel caso del &lt;strong&gt;ThreadPool&lt;/strong&gt;, quell'insieme di thread già pronti all'uso, utilizzati quando si chiama la Begin*** di un delegate o si usa &lt;strong&gt;ThreadPool.QueueUserWorkItem&lt;/strong&gt;, il campo statico risulta visibile alle operazioni che verranno prese in carico dal medesimo thread e mai rilasciato (si pensi al Dispose dell'oggetto) se non sovrascritto o impostato a null (il ThreadPool nel .NET 2.0 è composta da 25 Thread per CPU e di 500 IO Thread per CPU, in ASP.NET 2.0 sono 100/100, nel.NET 3.5 sono diventanti 250/500, mentre in ASP.NET 3.5 nella modalità AutoConfig sono rimasti invariati).&lt;/p&gt;&lt;p&gt;Per risolvere questo problema viene in aiuto la classe &lt;strong&gt;CallContext&lt;/strong&gt; (System.Runtime.Remoting.Messaging) con i metodi &lt;strong&gt;LogicalGetData&lt;/strong&gt; e &lt;strong&gt;LogicalSetData&lt;/strong&gt; per leggere e impostare in base ad una chiave il riferimento ad un oggetto. Il comportamento è simile a ThreadStatic, ma questi valori sono relativi al contesto in cui sono stati impostati. Per capire meglio ho creato questa classe:&lt;/p&gt;&lt;p&gt;&lt;code&gt;public class MyObject : Component &lt;br /&gt;{ &lt;br /&gt;private readonly string _name; &lt;/p&gt;&lt;p&gt;public MyObject(string name) &lt;br /&gt;{ &lt;br /&gt;    _name = name; &lt;br /&gt;} &lt;/p&gt;&lt;p&gt;protected override void Dispose(bool disposing) &lt;br /&gt;{ &lt;br /&gt;    base.Dispose(disposing); &lt;/p&gt;&lt;p&gt;    Console.WriteLine(&amp;quot;Disposed {0}&amp;quot;, _name); &lt;br /&gt;} &lt;/p&gt;&lt;p&gt;public override string ToString() &lt;br /&gt;{ &lt;br /&gt;    return _name; &lt;br /&gt;} &lt;br /&gt;}&lt;/code&gt;&lt;/p&gt;&lt;p&gt;E' una semplice classe che implementa &lt;strong&gt;IDisposable&lt;/strong&gt; così da sapere quando l'oggetto, identificato con un nome, viene distrutto. Poi ho creato una ConsoleApplication che esegue su un thread del pool il controllo di un campo marcato con ThreadStatic, lo valorizza se è nullo e ne stampa il valore. La stessa operazione viene effettuata usando CallContext. Inoltre, attendo la fine dell'esecuzione per assicurarmi che le altre successive operazioni vengono effettuate nuovamente sul medesimo thread ed utilizzo &lt;strong&gt;GC.Collect&lt;/strong&gt; per assicurarmi che gli oggetti, non più in uso, vengano distrutti (mi raccomando, in vere applicazioni non si deve chiamare se non in rare eccezioni):&lt;/p&gt;&lt;p /&gt;&lt;p&gt;&lt;code&gt;class Program &lt;br /&gt;{ &lt;/p&gt;&lt;p&gt;[ThreadStatic] &lt;br /&gt;private static object threadState; &lt;/p&gt;&lt;p&gt;static void Main(string[] args) &lt;br /&gt;{ &lt;br /&gt;    // Metodo da invocare su un Thread del pool &lt;br /&gt;    WaitCallback wc = DoWork; &lt;/p&gt;&lt;p&gt;    for (int x = 0; x &amp;lt; 3; x++) &lt;br /&gt;    { &lt;br /&gt;        // Invoco e attendo che finisca &lt;br /&gt;        wc.BeginInvoke(null, EndWork, wc).AsyncWaitHandle.WaitOne(); &lt;/p&gt;&lt;p&gt;        // Forzo la liberazione degli oggetti &lt;br /&gt;        GC.Collect(); &lt;br /&gt;        GC.WaitForPendingFinalizers(); &lt;br /&gt;    } &lt;/p&gt;&lt;p&gt;    // Avvio l'operazione su un nuovo Thread &lt;br /&gt;    Thread t = new Thread(DoWork); &lt;br /&gt;    t.Start(); &lt;br /&gt;    t.Join(); &lt;/p&gt;&lt;p&gt;    // Forzo la liberazione degli oggetti &lt;br /&gt;    GC.Collect(); &lt;br /&gt;    GC.WaitForPendingFinalizers(); &lt;/p&gt;&lt;p&gt;    Console.Read(); &lt;br /&gt;} &lt;/p&gt;&lt;p&gt;private static void EndWork(IAsyncResult ar) &lt;br /&gt;{ &lt;br /&gt;    ((WaitCallback)ar.AsyncState).EndInvoke(ar); &lt;br /&gt;} &lt;/p&gt;&lt;p&gt;const string DataKey = &amp;quot;test&amp;quot;; &lt;/p&gt;&lt;p&gt;static void DoWork(object state) &lt;br /&gt;{ &lt;br /&gt;    Console.WriteLine(&amp;quot;-----------------&amp;quot;); &lt;br /&gt;    Console.WriteLine(&amp;quot;Thread {0}&amp;quot;, Thread.CurrentThread.ManagedThreadId); &lt;/p&gt;&lt;p&gt;    object t = CallContext.LogicalGetData(DataKey); &lt;br /&gt;    if (t == null) &lt;br /&gt;    { &lt;br /&gt;        t = new MyObject(&amp;quot;LogicalData&amp;quot;); &lt;br /&gt;        Console.WriteLine(&amp;quot;LogicalData set&amp;quot;); &lt;br /&gt;        CallContext.LogicalSetData(DataKey, t); &lt;br /&gt;    } &lt;br /&gt;    else &lt;br /&gt;        Console.WriteLine(&amp;quot;LogicalData: {0}&amp;quot;, t); &lt;/p&gt;&lt;p&gt;    t = threadState; &lt;br /&gt;    if (t == null) &lt;br /&gt;    { &lt;br /&gt;        t = new MyObject(&amp;quot;DataThread&amp;quot;); &lt;br /&gt;        threadState = t; &lt;br /&gt;        Console.WriteLine(&amp;quot;DataThread set&amp;quot;); &lt;br /&gt;    } &lt;br /&gt;    else &lt;br /&gt;        Console.WriteLine(&amp;quot;DataThread: {0}&amp;quot;, t); &lt;br /&gt;    } &lt;br /&gt;}&lt;/code&gt;&lt;/p&gt;&lt;p&gt;Se lo si esegue, il risultato è il seguente:&lt;/p&gt;&lt;p&gt;&lt;code&gt;----------------- &lt;br /&gt;Thread 6 &lt;br /&gt;LogicalData set &lt;br /&gt;DataThread set &lt;br /&gt;----------------- &lt;br /&gt;Thread 6 &lt;br /&gt;LogicalData set &lt;br /&gt;DataThread: DataThread &lt;br /&gt;Disposed LogicalData &lt;br /&gt;----------------- &lt;br /&gt;Thread 6 &lt;br /&gt;LogicalData set &lt;br /&gt;DataThread: DataThread &lt;br /&gt;Disposed LogicalData &lt;br /&gt;Disposed LogicalData &lt;br /&gt;----------------- &lt;br /&gt;Thread 11 &lt;br /&gt;LogicalData set &lt;br /&gt;DataThread set &lt;br /&gt;Disposed DataThread&lt;/code&gt;&lt;/p&gt;&lt;p&gt;Come si vede, alla prima esecuzione di DoWork, entrambi i modi di memorizzare MyObject impostano il valore. Alla seconda esecuzione CallContext è di nuovo vuoto e va rivalorizzato, mentre threadState contiene il valore impostato sulla prima esecuzione. Lo stesso avviene anche alla terza esecuzione. E' interessante notare che l'oggetto impostato con CallContext viene effettivamente rilasciato e quindi ucciso dal GC solo all'avviarsi della nuova operazione sul medesimo thread (infatti il primo GC.Collect non ha sortito nessun effetto). Poiché i thread del pool non muoiono mai, DataThread non viene mai eliminato, ad eccezione di quello impostato nel Thread creato manualmente (l'esecuzione è finita e quindi il thread è inutilizzabile). &lt;br /&gt;Tutto questo meccanismo è gestito dalla classe &lt;strong&gt;ExecutionContext&lt;/strong&gt; (System.Threading) che è in grado di catturare, mettere a disposizione o di togliere il contesto e tutti valori ad esso associati. Quando si chiama ThreadPool.QueueUserWorkItem o il Begin*** di un metodo, viene chiamato ExecutionContext.Capture per catturare il contesto e tenerselo pronto quando il thread prende in consegna il delegate da eseguire, ripristinando quindi il contesto chiamando il metodo Run. Se avete mai dovuto creare un vostro ThreadPool, tipo &lt;a onclick="function anonymous()
{
function anonymous()
{
function anonymous()
{
blankUrl(this.href); return false;
}
}
}" href="http://msdn.microsoft.com/msdnmag/issues/06/03/netmatters/"&gt;questo&lt;/a&gt;, avrete sicuramente avuto a che fare con questa classe. Il bello di questo meccanismo è che se usiamo CallContext per mantenere dei valori ed invochiamo delegate asincroni o creiamo thread, automaticamente il contesto viene passato sull'altro thread condividendolo per la durata dell'operazione. Se nell'esempio precedente quindi si imposta prima di qualsiasi accodamento, l'istruzione CallContext.LogicalSetData(DataKey, new MyObject(&amp;quot;test&amp;quot;)); si ottiene a console:&lt;/p&gt;&lt;p /&gt;&lt;p&gt;&lt;code&gt;Thread 6 &lt;br /&gt;LogicalData: test &lt;br /&gt;DataThread set &lt;br /&gt;----------------- &lt;br /&gt;Thread 6 &lt;br /&gt;LogicalData: test &lt;br /&gt;DataThread: DataThread &lt;br /&gt;----------------- &lt;br /&gt;Thread 6 &lt;br /&gt;LogicalData: test &lt;br /&gt;DataThread: DataThread &lt;br /&gt;----------------- &lt;br /&gt;Thread 11 &lt;br /&gt;LogicalData: test &lt;br /&gt;DataThread set &lt;br /&gt;Disposed DataThread&lt;/code&gt;&lt;/p&gt;&lt;p&gt;Si noti che LogicalData su tutti i thread è già impostato.&lt;/p&gt;&lt;p&gt;Un'ultimo aspetto riguarda ASP.NET che utilizza anch'esso CallContext.HostContext ogni qualvolta si interroga HttpContext.Current, ma se si usano pagine asincrone con task ecc, i metodi asincroni non dispongono del contesto web e HttpContext.Current ritorna null. Diversamente usando CallContext.LogicalSetData si ha a disposizione l'oggetto anche sui task asincroni ed è quindi l'ideale se dovete mantenere DataContext (LINQ) o Session (NHibernate).&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;a href="http://www.aspitalia.com/"&gt;(C) 2008 ASPItalia.com Network - All rights reserved&lt;/a&gt;&lt;/p&gt;</description><dc:creator>Cristian "Ricciolo" Civera</dc:creator><category>.NET</category><guid isPermaLink="true">http://blogs.aspitalia.com/ricciolo/post2187/Curiosita-Thread.aspx</guid><slash:comments>4</slash:comments><wfw:comments>http://blogs.aspitalia.com/ricciolo/post2187/Curiosita-Thread.aspx#feedback</wfw:comments><wfw:commentRss>http://blogs.aspitalia.com/ricciolo/CommentRSS2187.aspx</wfw:commentRss><trackback:ping>http://blogs.aspitalia.com/services/trackback.aspx?PostID=2187</trackback:ping></item></channel></rss>