Non poter creare query dinamiche è un limite di LINQ che si fa sentire ogni volta che si devono generare, ad esempio, query derivate da input attraverso l’interfaccia utente.
Un esempio classico è una pagina web in cui è visualizzata una tabella di dati. Se si vuole implementare l’ordinamento delle colonne o un filtraggio dei dati con parametri impostati dall’utente, infatti, si devono creare delle query al volo che dipendono dagli input dell’utente.
Per farlo via codice, si è costretti a concatenare alla query LINQ le condizioni del Where, con una serie di if per analizzare l’input dell’utente e decidere cosa concatenare e cosa no. Analogamente per l’OrderBy.
Un semplice ordinamento in seguito al click dell’utente, ad esempio, può essere implementato così:
public static IQueryable<SecurityEntity> GetSecuritiesOrdered
(IQueryable<SecurityEntity> securities, string sortExpression, string sortDirection)
{
switch (sortExpression)
{
case "Exchange":
securities = sortDirection == "DESC"
? securities.OrderByDescending(s => s.Exchange)
: securities.OrderBy(s => s.Exchange);
break;
case "ISIN":
securities = sortDirection == "DESC"
? securities.OrderByDescending(s => s.ISIN)
: securities.OrderBy(s => s.ISIN);
break;
case "Country":
securities = sortDirection == "DESC"
? securities.OrderByDescending(s => s.Country)
: securities.OrderBy(s => s.Country);
break;
//...
}
return securities;
}
È tuttavia possibile creare query dinamiche con linq, utilizzando una comoda libreria il cui codice è scaricabile da qui. Basta includere nel proprio progetto la classe System.Linq.Dynamic, il cui codice è nell’esempio (nella cartella \LinqSamples\DynamicQuery).
Con questa libreria, il metodo visto prima diventa semplicemente:
public static IQueryable<SecurityEntity> GetSecuritiesOrdered
(IQueryable<SecurityEntity> securities, string sortExpression, string sortDirection)
{
return securities.OrderBy(string.Format("{0} {1}", sortExpression, sortDirection));
}
Nel codice di esempio si vede come si possano creare query del tipo:
var query =
db.Customers.Where("City == @0 and Orders.Count >= @1", "London", 10).
OrderBy("CompanyName").
Select("New(CompanyName as Name, Phone)");
Per approfondimenti si può fare riferimento a questo post di Scott Guthrie.
Quando si crea un progetto su Visual Studio per Windows Azure, in ogni ruolo aggiunto viene creata una classe WorkerRole o WebRole, a seconda del ruolo scelto. Entrambe queste classi sono implementazioni della classe astratta RoleEntryPoint. Per ogni istanza, Window Azure avvia solo una classe di RoleEntryPoint, pertanto non è possibile sulla stessa istanza, ad esempio, avviare un WebRole ed un WorkerRole contemporaneamente.
Una soluzione consiste nel far girare i ruoli su thread diversi. Per farlo si può utilizzare un comodo framework scritto da Wayne Walter Berry.
In questo framework si trova la classe ThreadedRoleEntryPoint che eredita da RoleEntryPoint e deve essere usata per sostituirlo nel WorkerRole di default, che dovrà ereditare quindi da questa classe.
public class WorkerRole : ThreadedRoleEntryPoint
Invece i worker che si vogliono far partire su thread diversi devono ereditare da un’altra classe astratta del framework, WorkerEntryPoint, che ripropone gli stessi metodi del RoleEntryPoint, ma non ha il limite di ammettere una sola classe derivata che gira su Azure.
public class MyWorker : WorkerEntryPoint
A questo punto per far partire i worker in thread diversi basta implementare l’override del metodo OnStart nella classe WorkerRole creando una lista di istanze di sottoclassi di WorkerEntryPoint.
public override bool OnStart()
{
List<WorkerEntryPoint> workers = new List<WorkerEntryPoint>();
workers.Add(new MyWorker());
workers.Add(new MyOtherWorker());
workers.Add(new MyWebRole());
workers.Add(new MyThirdWorker());
workers.Add(new MyThirdWorker());
workers.Add(new MyThirdWorker());
return base.OnStart(workers.ToArray());
}
Il metodo OnStart della classe base ThreadedRoleEntryPoint provvederà ad avviare ciascuno dei worker in un thread separato.
Tutti i dettagli nel post Running Multiple Threads on Windows Azure di Wayne Walter Berry, da dove è possibile anche scaricare il codice completo.
I siti web ASP.NET utilizzano algoritmi per criptare, decifrare e validare il viewstate, i dati di autenticazione mediante form e l’identificazione della sessione ASP.NET in modalità out of process, quindi per esempio per siti pubblicati su più server di una server farm.
Gli algoritmi e le relative chiavi di validazione e decrittazione sono configurabili nel file web.config attraverso l’elemento machineKey.
Le impostazioni di default di IIS prevedono che ad ogni sito sia assegnata automaticamente una chiave di validazione e una per decriptare. Però queste impostazioni non vanno bene, ad esempio, per siti pubblicati in load balancing su una web farm, poiché per consentire alla sessione di seguire l’utente mentre viene dirottato da un server verso un altro, è necessario che su tutti i server gli algoritmi e le chiavi coincidano.
È necessario, perciò, generare le chiavi e per farlo si possono utilizzare i numerosissimi tool on line, oltre che scriversene uno seguendo gli altrettanto numerosi tutorial on line.
Oppure si può usare lo stesso IIS 7 (o successivo) per configurare gli algoritmi e generare le chiavi, come suggerito qui, attraverso la funzionalità offerta da IIS Manager.

Dal sito che ci interessa, cliccando su “Chiave computer” si accede alla funzionalità specifica, in cui si può deselezionare l’opzione di generazione automatica in fase di esecuzione e poi, cliccando su “Genera chiavi”, far generare le chiavi.

Applicando le modifiche, nel file web.config del sito viene scritto l’elemento machineKey, ad esempio:
<configuration>
<system.web>
<machineKey decryption="AES" decryptionKey="99CF7A9B2A1D1B954A1800A714C3BFD0927AEAD93DBEA93B"
validationKey=
"F53F821100A97C0718E481ACDE9EDDFBA360A8882A4F88ECC29D6029D9053CE1A94EC95A29C51556E19C6B918DB342F8B78C634AA59CC4C3CE0D86A0BE3CFB16"
/>
</system.web>
</configuration>
Gli stessi valori dovranno essere riportati nei web.config del sito di tutti i server della web farm.
ClipX è un tool di cui ormai non riesco più a fare a meno. Si tratta di un clipboard history manager: memorizza quello che si è salvato nella clipboard di Windows e ne consente il recupero, sfogliando la clipboard history. Si può così recuperare ciò che si era salvato in precedenza, anche in una precedente sessione, e funziona pure con le bitmap.
Questo semplice tool, secondo me, migliora notevolmente l’utilizzo della clipboard, una delle poche cose che è rimasta immutata per molti anni attraverso i sistemi operativi. È configurabile e leggero e da quando lo uso (qualche anno ormai) non ho riscontrato problemi, anche con la versione a 64 bit, che è etichettata come beta (1.0.3.9 beta 7 x64).
L’unico inconveniente l’ho riscontrato utilizzandolo con UAC attivato e provando a incollare dalla clipboard history in un’applicazione che gira con privilegi amministrativi, ad esempio Visual Studio.
In tal caso si può far partire anche ClipX con privilegi amministrativi, autorizzandolo quando si presenta il prompt di UAC, e tutto funziona regolarmente.
Oppure bisogna fare due passaggi. Con il primo si incolla da ClipX nell’applicazione con privilegi amministrativi. Anche se l’operazione sembra andare a vuoto, quello che si cercava di recuperare dalla clipboard history è finito direttamente nella clipboard. Pertanto con un secondo passaggio è possibile incollare dalla clipboard nell’applicazione.
Il consiglio è di provarlo, ma attenzione: dà dipendenza :-)