Come inizializzare una Hashtable in C# 3.0

Tra le novità introdotte dalla versione 3.0 del .NET framework troviamo gli "Initializers" normalmente utilizzati per inizializzare le proprietà di un oggetto direttamente nella chiamata al costruttore, ad esempio:

Person aPerson = new Person(){ Name = "Mario", Surname = "Rossi" };

Analogamente possiamo utilizzare la stessa funzionalità anche per le collezioni e nello specifico vediamo come inizializzare una Hashtable:

Hashtable aCollection = new Hashtable(){ 
                               { "Key1", "Value1" }, 
                               { "Key2", "Value2" } 
};

Modificare lo schema di una tabella in SQL

Per chi ha un sito in hosting su Aruba conosce bene la necessità di dover specificare come schema degli oggetti del database il nome assegnato dal provider, che poi è lo stesso del db. In questi giorni mi sono imbattuto in questa problematica dovendo aggiornare questo blog all'ultima versione di BlogEngine.NET, da qui la necessità di cambiare lo schema predefinito dbo con quello fornito da Aruba. Ecco come farlo con una query SQL:

ALTER SCHEMA MSSql0001 TRANSFER dbo.be_Users

Model View Controller: slide e demo disponibili per il download

Per chi fosse interessato sono disponibili per il download le slide e la demo dell'evento di giovedì scorso organizzato da 1nn0va sul Model View Controller. Nella demo i progetti di esempio con il confronto tra WebForms, ASP.NET MVC e MonoRail.

Per scaricare i file cliccare sui link qui sotto:


Eseguire codice JavaScript contenuto in una response Ajax

Ajax consente l'aggiornamento dinamico di una pagina web, ma se nel contenuto della response è presente del codice JavaScript questo non viene eseguito.
Come possiamo risolvere questo problema?

Cercando in rete ho trovato che la soluzione più semplice è quella di estrarre con una regular expression il codice all'interno del tag <script> e di passarlo alla funzione eval(). Vediamo in dettaglio un esempio utilizzando per la chiamata Ajax la libreria prototype:

var regex = /]*>([\s\S]*?)<\/script>/gm;

function DoAjax(url)
{
  new Ajax.Request(url,
      {
         method: 'get',
         onSuccess: updateAjaxArea,
         onFailure: showMessage
      });
}

function updateAjaxArea(transport)
{
  $('ajaxarea').innerHTML = transport.responseText;
  var str = transport.responseText; 
  var scripts = str.match(regex);
  eval(scripts[0].replace(/(<\s*\/?\s*)script(\s*([^>]*)?\s*>)/gi,''));
}

function showMessage(transport)
{
  alert('An error occurred during the AJAX request.');
}

Eseguire dei filtri nei file xml di mapping in NHibernate con la proprietà where

Immaginiamo di avere una collection di oggetti mappati con un bag in NHibernate e di volerli ottenere già filtrati dal database per una particolare condizione. Sembrerebbe un lavoro da where ed infatti non a caso sfogliando tra gli attributi dell'elemento bag troviamo proprio l'attributo where, ma vediamo in un esempio come utilizzarlo:



  
  ...     
  
     
        
     
     
  
  


Monorail & NVelocity: primo e ultimo elemento di un ciclo foreach

Può capitare alle volte di voler distinguere l'output di un foreach per il primo oppure l'ultimo elemento del ciclo, per fare questo in MonoRail il view engine NVelocity ci mette a disposizione la variabile $velocityCount che possiamo utilizzare nel seguente modo:


   #foreach($item in $items)
      #if($velocityCount == 1)
      
         
      
      #elseif($velocityCount == $items.Count)
      
         
      
      #else
      
         
      
      #end
   #end
I'm the first row!
I'm the last row!
 

Fonte: Just in ram


String Concatenation in C# Benchmark

Ci sono diversi modi per concatenare una stringa in C# : con String.Concat,  utilizzando uno StringBuilder, con String.Format oppure ricorrendo all'overloading dell'operatore +. Spinto dalla curiosità di sapere quale di questi modi fosse il più performante ho realizzato un semplice test:

using System;
using System.Text;
using System.Diagnostics;

public class Program
{
   static void Main(string[] args)
   {
      Console.WriteLine("String concatenation benchmark");
      Console.WriteLine("------------------------------");
      Console.WriteLine("Plus operator: " + StringPlusOperatorTest());
      Console.WriteLine("String.Format: " + StringFormatTest());
      Console.WriteLine("String.Concat: " + StringConcatTest());
      Console.WriteLine("StringBuilder: " + StringBuilderTest());
      Console.ReadLine();
   }

   private static string StringPlusOperatorTest()
   {
      Stopwatch sw = new Stopwatch();
      sw.Start();
      string result = String.Empty;
      for (int i = 0; i < 10000000; i++)
      {
      result = i + " Nel mezzo del cammin di nostra vita, " 
            + "mi ritrovai per una selva oscura" 
            + " ché la diritta via era smarrita.";
      }
      sw.Stop();
      TimeSpan ts = sw.Elapsed;
      return String.Format("{0:00}:{1:00}:{2:00}.{3:00}", 
         ts.Hours, ts.Minutes, ts.Seconds,
         ts.Milliseconds / 10);
   }

   private static string StringFormatTest()
   {
      Stopwatch sw = new Stopwatch();
      sw.Start();
      string result = String.Empty;
      for (int i = 0; i < 10000000; i++)
      {
         result = String.Format("{0}{1}{2}{3}", 
            i, " Nel mezzo del cammin di nostra vita, ", 
            "mi ritrovai per una selva oscura", 
            " ché la diritta via era smarrita.");
      }
      sw.Stop();
      TimeSpan ts = sw.Elapsed;
      return String.Format("{0:00}:{1:00}:{2:00}.{3:00}", 
         ts.Hours, ts.Minutes, ts.Seconds,
         ts.Milliseconds / 10);
   }

   private static string StringConcatTest()
   {
      Stopwatch sw = new Stopwatch();
      sw.Start();
      string result = String.Empty;
      for (int i = 0; i < 10000000; i++)
      {
         result = String.Concat(i, 
            " Nel mezzo del cammin di nostra vita, ", 
            "mi ritrovai per una selva oscura", 
            " ché la diritta via era smarrita.");
      }
      sw.Stop();
      TimeSpan ts = sw.Elapsed;
      return String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
         ts.Hours, ts.Minutes, ts.Seconds,
         ts.Milliseconds / 10);
   }

   private static string StringBuilderTest()
   {
      Stopwatch sw = new Stopwatch();
      sw.Start();
      for (int i = 0; i < 10000000; i++)
      {
         StringBuilder sb = new StringBuilder();
         sb.Append(i);
         sb.Append(" Nel mezzo del cammin di nostra vita, ");
         sb.Append("mi ritrovai per una selva oscura");
         sb.Append(" ché la diritta via era smarrita.");
      }
      sw.Stop();
      TimeSpan ts = sw.Elapsed;
      return String.Format("{0:00}:{1:00}:{2:00}.{3:00}", 
         ts.Hours, ts.Minutes, ts.Seconds,
         ts.Milliseconds / 10);
   }

Il test consiste nel concatenare tre stringhe più un contatore. Data la semplicità dell'operazione per avere dei risultati misurabili ho dovuto inserire l'operazione in un ciclo for. Dai risultati visibili nell'immagine qui sotto si può notare come l'operatore + sia il più veloce seguito dal metodo String.Concat e a grande distanza dagli altri due metodi...

 StringConcatBenchmark

Se però consideriamo una concatenazione con più stringhe (42 per la precisione) otteniamo i risultati visibili nell'immagine sottostante. L'operatore + è ancora il migliore, ma il metodo String.Concat peggiora notevolemente forse per il numero cospicuo di parametri.

 StringConcatBenchmark2

Per quanto possa essere misurabile e percepita dall'utente la differenza di performance questo test conferma una banalità, usare String.Concat per la concatenazione di stringhe e String.Format per la formattazione. :-)


Impostare la pagina di default con MonoRail Routing HttpModule

Oggi ho avuto l'occasione di utilizzare il Routing di MonoRail per risolvere un problema da tempo in sospeso, ovvero chiamare l'action di default quando nell'indirizzo viene specificato solo il nome del controller. Ad esempio se digitiamo mysite.com/admin MonoRail deve essere in grado di richiamare mysite.com/admin/default.rails.
La prima cosa da fare è creare nella root del sito la cartella admin con all'interno una pagina Default.aspx senza code-behind. In questo modo ASP.NET riscriverà la chiamata a mysite.com/admin con l'indirizzo mysite.com/admin/Default.aspx. In secondo luogo dobbiamo registrare nel web.config l'HttpModule di Routing:


 
 
 

A questo punto possiamo dichiarare delle regole di routing specificando con le regular expression quali indirizzi considerare e come eseguirne la riscrittura:


   
   
      
         (\b/\w+)/?Default.aspx$
         
      
      
         (/Default.aspx)
         
      
   

Nell'esempio sono state registrare due regole, nella prima vengono considerati tutti gli indirizzi che iniziano con il carattere / seguito da almeno un carattere alfanumerico e che terminano con un carattere / e la stringa Default.aspx, questi indirizzi vengono riscritti prendendo la parte prima del Default.aspx aggiungendovi /default.rails. La seconda regola invece ci permette di intercettare le chiamate alla pagina Default.aspx che si trova nella root del sito e che con la logica della prima regola porterebbe ad un controller vuoto e di conseguenza ad una bella eccezione. In questo caso l'indirizzo viene sostituito con /home/default.rails.

Nota: Per utilizzare questa tecnica è necessario creare una Default.aspx con relativa cartella per ogni controller dell'applicazione o meglio per i controller che necessitano di una pagina di default.


Le migliori shortcuts di Visual Studio 2008

Le shortcuts sono sicuramente la via più breve e semplice per migliorare la produttività. Ecco un elenco delle migliori tra quelle a disposizione con Visual Studio 2008:

  • [CTRL] + [SHIFT] + [B] -> esegue il build della solution
  • [CTRL] + [SHIFT] + [S] -> salva tutti i file aperti
  • [CTRL] + [I] -> attiva la funzione di ricerca incrementale. Dopo aver premuto tale combinazione digitare la chiave di ricerca ed una volta completata la chiave spostarsi in avanti sempre con CTRL + I ed indietro con CTRL + SHIFT + I
  • [F5] e [SHIFT] + [F5] -> il primo fa partire il debug l'altro lo interrompe
  • [SHIFT] + [F9] -> pone la variabile selezionata dal cursore sotto "Quick Watch"
  • [CTRL] + [SHIFT] + [Space] -> posizionandosi all'interno della chiamata di un metodo permette di vedere in un tooltip la lista di parametri richiesta dal metodo
  • [CTRL] + [.] -> apre la finestra smart tag utile in caso di inserimento di uno using per un tipo sconosciuto
  • ([CTRL] + [K]) + [F]-> esegue la formattazione della selezione corrente
  • ([CTRL] + [K]) + [C] e ([CTRL] + [K]) + [U] -> il primo commenta le righe selezionate, l'altro esegue l'operazione inversa
  • [ALT] + [SHIFT] + [Enter] -> attiva la modalità FULL SCREEN, ripremere la stessa combinazione di tasti per disattivare la modalità
  • ([CTRL] + [\]) + [D] -> apre la finestra Code Definition per il tipo sotto cursore
  • [CTRL] + [SHIFT] + [F] -> permette di eseguire la funzione di ricerca nei file del progetto
  • [SHIFT] + [Canc] -> cancella la riga corrente salvandola negli appunti
  • [CTRL] + [-] e [CTRL] + [SHIFT] + [-] -> sposta il cursore nella posizione successiva o precedente
  • [F12] -> esegue il "Go to definition"

Tra le più curiose ci sono invece:

  • [CTRL] + [ì] -> se mi posiziono su una parentesi di un blocco di codice ed eseguo questa combinazione di tasti il cursore si posiziona sull'altra parentesi che delimita il blocco
  • [CTRL] + [SHIFT] + [ì] -> se mi posiziono su una parentesi di un blocco di codice con questa combinazione seleziono tutto il blocco di codice
  • [CTRL] + []] -> seleziona il pezzo di codice compreso tra il cursore e l'ultima posizione di modifica
  • [CTRL] + [T] ->inverte le lettere ai lati del cursore

E se non ci bastano dalla finestra Tools > Options > Keyboard ne possiamo creare di nuove:

Shortcuts


Come indicizzare una proprietà di un tipo non primitivo in Lucene.Net con un FieldBridge di NHibernate.Search

Può essere utile a volte indicizzare con Lucene.Net una proprietà di un oggetto che non sia una stringa o un tipo primitivo, pensiamo ad esempio alla lista di categorie di un prodotto. Per casi come questo e laddove l'accesso ai dati viene fatto con NHibernate posso raggiungere il risultato desiderato utilizzando un FieldBridge di NHibernate.Search ed un po' di reflection:

public class PropertyBridge 
      : ITwoWayStringBridge, IParameterizedBridge
{
  private Type _type;
  private string _propertyName;
  
  public string ObjectToString(object obj)
  {
    StringBuilder sb = new StringBuilder();
    PropertyReflector pr = new PropertyReflector();
    if (obj.GetType().IsGenericType && 
      typeof(PersistentGenericBag<>).IsAssignableFrom(
          obj.GetType().GetGenericTypeDefinition()))
    {
      IEnumerable enumerable = obj as IEnumerable;
      if (enumerable != null)
      {
        IEnumerator enumerator = enumerable.GetEnumerator();
  
        while (enumerator.MoveNext())
        {
          object current = enumerator.Current;
          if(current!=null)
          {
            sb.Append(pr.GetValue(current,_propertyName) + " ");
          }
        }
        return sb.ToString();
      }
    }
    else
    {
      sb.Append(pr.GetValue(obj,_propertyName));
    }
    return sb.ToString();
  }
  
  public void SetParameterValues(object[] parameters)
  {
    Object classType = parameters[0];
    if (classType != null)
      this._type = (Type)classType;
    _propertyName = parameters[1].ToString();
  }
 
  public object StringToObject(string stringValue)
  {
    throw new NotImplementedException();
  }
}

Il FieldBridge permette a NHibernate.Search di indicizzare con Lucene il contenuto di una proprietà qualora non fosse coerente utilizzare il metodo ToString() (quasi mai per i tipi non primitivi). Analizzando il codice sopra riportato si può notare come vengano passati al FieldBridge due parametri: il tipo di oggetto ed il nome della proprietà da indicizzare (righe 38-44). Con questi due parametri ed utilizzando l'utility PropertyReflector (classe di utilità scritta da Guy Mahieu per fare "deep-reflection" di proprietà) viene recuperato il valore da salvare nell'indice di Lucene. Il FieldBridge in oggetto riesce ad indicizzare sia oggetti singoli (righe 31-34) sia collezioni verificandone il tipo ed utilizzando l'interfaccia IEnumerator (righe 11-30). Qui sotto possiamo notare l'utilizzo dell'attributo per una proprietà di tipo IList<T>.

[FieldBridge(typeof(PropertyBridge),new object[]{ typeof(Category), "CategoryID" })]
public virtual IList Categories { get; set; }

Nota: il PropertyBridge visto in questo esempio nasce da una esigenza specifica e per questo motivo non ricopre tutte le casistiche possibili.