Utilizzare dotless con Visual Studio 2010

Dotless è il porting di Less un linguaggio dinamico che estende le funzionalità dei css aggiungendo variabili, spazi dei nomi, funzioni, etc. Possiamo creare stili annidati, riutilizzare caratteristiche comuni, definire i colori del nostro sito in un solo punto. Sarà un "compilatore" a generare per noi il css da inviare al browser.

dotless

La generazione dei css può avvenire sia lato client (tramite una libreria javascript), sia lato server tramite un compilatore oppure da C# tramite un'API, ma vediamo come utilizzare dotless con Visual Studio.

Passo 1 - Installare dotless

Per installare dotless dovete lanciare dalla Package Manager Console di Visual Studio 2010 il comando Install-Package dotless. Al termine dell'operazione avrete nella cartella packages della solution tutto quello che serve per cominciare.

Passo 2 - Creare un file .less

Aggiungete al progetto un nuovo file di tipo testo e rinominatelo con estensione .less, per agevolarvi nella compilazione della sintassi potete installare l'add-in LessExtension che potete trovare tramite NuGet. Scrivete qualche riga di codice in "linguaggio" less, magari copiandola dal sito.

Passo 3 - Scrivere un file batch che compili i file .less

Il listato sottostante permette di chiamare il compilatore dotless passando come argomenti la cartella dove trovare i file .less e la destinazione dei file css compilati. Se i file css risultassero vuoti saranno cancellati dall'ultima istruzione (utile se definite un file .less contenente solo variabili).

for /f %%F in ('dir /b %2\*.less') do (
 call %1dotless.compiler.exe -m "%~2%%F" "%~3%%~nF.css"
)

cd %~3
for /F "delims=" %%I in ('dir /B *.css') do (
  if not exist "%%I\" if %%~zI EQU 0 del "%%I"
)

Passo 4 - Lanciare il batch in PreBuild

Per fare in modo che i file css siano generati prima dell'esecuzione del sito è necessario chiamare il file batch nell'evento Pre-Build del progetto. Andate quindi nella sezione "Build Events" delle proprietà del progetto e copiate il listato seguente nel campo Pre-build event command line.

call "$(ProjectDir)less2css.bat" 
            "$(SolutionDir)packages\dotless.1.2.1.0\tool\" 
            "$(ProjectDir)content\css\less\" 
            "$(ProjectDir)content\css\"

Gli argomenti passati sono il percorso dove trovare il compilatore, la cartella dei file .less e la cartella di destinazione dei file css.

Conclusioni

Ci sono altri modi di utilizzare less, se utilizzate less.js come compilatore potete addirittura definire le proprietà degli stili richiamando funzioni javascript. Al momento ho preferito sfruttare less solo lato server per mantenere il client più leggero ed avere maggior controllo sui css generati.

 


Tutte le novità di ASP.NET MVC3: Slide e codice dell'evento

Di seguito potete trovare le slide e il codice della mia sessione su Tutte le novità di ASP.NET MVC3.

Nota: Per eseguire il codice di esempio è necessario modificare i percorsi del file database che trovate nell'App_Data.

Codice di esempio pronto per il download >> Download


Non commentare il codice, rendilo più leggibile con le Fluent Interface

Ad ognuno di noi sarà capitato almeno una volta di leggere una porzione di codice e di non riuscire a capirne la logica. Tra le cause oltre al cattivo design c’è quasi sempre la mancanza di commenti o di documentazione. Ma quanti di noi commentano il codice che scrivono? Intendiamoci è una buona regola commentare il codice, ma è un’attività talmente noiosa che diventa inutile se poi non manteniamo il commento aggiornato.
Vediamo allora come applicando le “Fluent Interface” possiamo scrivere del codice che si commenta da solo!

Una interfaccia è “fluente” quando ci consente di rendere il codice implementativo leggibile come le righe di un romanzo oppure come le strofe di una poesia. Tale caratteristica non è soggettiva, ma si può ottenere facilmente partendo dalla tecnica del method chaining.

Il method chaining, ovvero la possibilità di concatenare le chiamate ai metodi di una interfaccia, si ottiene definendo come valore di ritorno l’istanza corrente della classe a cui appartiene il metodo.

Con un po’ di codice tutto sarà più chiaro. Vediamo quindi un esempio di interfaccia non “fluente” che riguarda la prenotazione di un biglietto ferroviario. Partiamo con la classe Train:
namespace FluentInterface.Model.NoFluent
{
    using System;
    using System.Text;

    public class Train
    {
        public string Number { get; set; }

        public string DepartureStation { get; set; }

        public string Destination { get; set; }

        public DateTime DepartureDate { get; set; }

        public int Class { get; set; }

        public Train(){ }

        public Train(string number, 
                     string departureStation, string destination, 
                     DateTime departureDate, int _class)
        {
            this.Number = number;
            this.DepartureStation = departureStation;
            this.Destination = destination;
            this.DepartureDate = departureDate;
            this.Class = _class;
        }
    }
}

Nel codice cliente andiamo poi a prenotare il biglietto per un particolare treno:

bookingService.PlaceBookingFor(
            new Train("9513", 
                      "Milano C.le", 
                      "Roma Termini", 
                      DateTime.Parse("2010/02/12 8:20"), 1)
);

Come possiamo notare il codice non è per niente leggibile, dobbiamo infatti ricorrere alla definizione del costruttore della classe per capire il significato dei parametri passati.

Grazie agli object initializer introdotti con la versione 3.0 di C# il codice si fa più chiaro, ma rimane ancora pesante da leggere:
bookingService.PlaceBookingFor(
    new Train()
    { 
      Number = "9513",
      DepartureStation = "Milano C.le",
      Destination = "Roma Termini",
      DepartureDate = DateTime.Parse("2010/02/12 8:20"),
      ClassNumber = 1
    }   
);

Vediamo quindi come una interfaccia “fluente” può rendere questo codice più leggibile:

namespace FluentInterface.Model.Fluent
{
    using System;
    using System.Text;

    public enum Class 
    {
        First = 1,
        Second = 2,
        Third = 3
    }

    public class Train
    {
        public string Number { get; set; }

        public string DepartureStation { get; set; }

        public string Destination { get; set; }

        public DateTime DepartureDate { get; set; }

        public int ClassNumber { get; set; }

        public Train(){ }

        public Train(string number, 
                     string departureStation, string destination, 
                     DateTime departureDate, int classNumber)
        {
            this.Number = number;
            this.DepartureStation = departureStation;
            this.Destination = destination;
            this.DepartureDate = departureDate;
            this.ClassNumber = classNumber;
        }

        #region Fluent Interface
        public Train Nr(string number)
        {
            this.Number = number;
            return this;
        }

        public Train From(string departureStation)
        {
            this.DepartureStation = departureStation;
            return this;
        }

        public Train To(string destination)
        {
            this.Destination = destination;
            return this;
        }

        public Train DepartureAt(DateTime departureDate)
        {
            this.DepartureDate = departureDate;
            return this;
        }

        public Train DepartureAt(string departureDate)
        {
            this.DepartureDate = DateTime.Parse(departureDate);
            return this;
        }

        public Train In(Class _class)
        {
            this.ClassNumber = (int)_class;
            return this;
        }
        #endregion
    }
}

Vediamo come cambia il nostro codice cliente per quanto riguarda la prenotazione di un biglietto ferroviario:

bookingService.PlaceBookingFor(new Train().Nr("9513")
                                          .From("Milano C.le")
                                          .To("Roma Termini")
                                          .DepartureAt("12/2/09 8:20")
                                          .In(Class.First));

Possiamo migliorare ancora trasformando il metodo Nr in una “static factory”, ovvero implementando al suo interno la creazione di una istanza della classe Train, così:

public static Train Nr(string number)
{
   Train train = new Train();
   train.Number = number;
   return train;
}

La differenza rispetto al codice di prima è minima, ma evidente:

bookingService.PlaceBookingFor(Train.Nr("9513")
                                    .From("Milano C.le")
                                    .To("Roma Termini")
                                    .DepartureAt("12/02/2009 8:20")
                                    .In(Class.First));

In conclusione ci sono molti modi per aiutare noi stessi e altri programmatori a capire che cosa fa il nostro codice, il più importante di tutti rimane sempre il commento, ma le fluent interface sono un valido alleato per combattere le lunghe sedute davanti al reflector!


WPF: Binding del contenuto di una Label con la proprietà di un altro controllo

Vediamo come collegare il contenuto di una label con la proprietà di un altro controllo, ad esempio per visualizzare il numero di elementi di una griglia:


MEF in Action: slide e codice dell'evento

Grande partecipazione ieri sera all'hands on lab organizzato da 1nn0va presso il Consorzio Universitario di Pordenone. Di seguito potete trovare le slide e il codice della mia sessione sul Managed Extensibility Framework.

Nota: Per eseguire il programma è necessario verificare i percorsi del file database che trovate nell'App.Config, del foglio excel all'interno del progetto HelloMEF.Plugin e il percorso della cartella dove caricare i plugin all'interno del progetto principale HelloMEF.

 

Codice di esempio pronto per il download >>
Download


Verificare l'esistenza di una variabile in una pagina con JavaScript

Ecco come verificare in JavaScript se una certa variabile è stata definita all'interno della pagina:

if(typeof(pippo) != 'undefined'){
 //do something with pippo
}

AntiPatterns, i vizi del programmatore: slide e codice

Ho pubblicato su slideshare le slide dell'evento 1nn0va di venerdì sera. Per chi fosse interessato sono disponibili per il download i progetti di esempio, trovate il link qui sotto dopo la presentazione.

 

Codice di esempio pronto per il download >>
Download

Managed Extensibility Framework (MEF)

Come posso sviluppare un'applicazione che tenga conto di codice non ancora scritto?
Come posso estendere la mia applicazione senza doverla ridistribuire ogni volta?
Con l'aiuto di MEF posso fare questo e molto altro!

Managed Extensibility Framework (o MEF) è una libreria tutta nuova distribuita con il .NET Framework 4.0 sviluppata per risolvere problemi di estendibilità delle applicazioni, ovvero per poter strutturare in modo rapido e trasparente un'architettura a plug-in.

mef

Come funziona MEF

MEF riesce a comporre le parti di un sistema con architettura a plug-in grazie a due specifiche:

  • Una coppia di attributi [Import]/[Export]. [Import] viene utilizzato per decorare le parti dell'applicazione che espongono un servizio, mentre [Export] definisce le implementazioni di quel servizio (i plug-in appunto)
  • Un catalogo che definisce dove MEF deve cercare per trovare le implementazioni da associare al servizio definito nell'applicazione
MEF_Diagram

MEF in Action: un esempio

Vogliamo sviluppare un'applicazione che visualizzi all'utente una serie di notizie provenienti da fonti diverse, le fonti devo poterle caricare a runtime.

Prima di tutto devo indicare a MEF il "punto di estensione" dell'applicazione, ovvero una proprietà IEnumerable generica con tipo l'interfaccia che i vari plug-in dovranno poi implementare e lo faccio semplicemente decorando la proprietà con l'attributo [ImportMany].

namespace MEF.Console
{
    class Program
    {
        [ImportMany]
        public IList NewsService { get; set; }

        public Program()
        {
            NewsService = new List();
        }

        static void Main(string[] args)
        {
...

Ed ecco l'interfaccia definita in un assembly esterno.

namespace MEF.PluginInterface
{
  using System;

  public interface INewsService
  {
    string Source { get; }
    string[] NewsOf(DateTime day);
  }
}

Creiamo poi un plug-in che implementi questa interfaccia. Per indicare a MEF che si tratta di un plug-in dell'applicazione devo decorare la classe che implementa il servizio con l'attributo [Export]

namespace Ansa
{
    using System;
    // namespace di MEF
    using System.ComponentModel.Composition;
    using MEF.PluginInterface;

    [Export(typeof(INewsService))]
    public class AnsaNewsService : INewsService
    {
        public string Source {
            get { return "Ansa"; }
        }

        public string[] NewsOf(DateTime day)
        {
            return new string[] 
            { 
                "Internet: Amazon debutta in Italia",
                "Evento 1nn0va sugli Anti-Pattern!"
            };
        }
    }
}

Come ultimo passaggio devo indicare a MEF come trovare i plug-in. Devo definire un catalogo, che nel nostro esempio sarà di tipo Directory, devo creare un container su quel catalogo e utilizzarlo per comporre le parti del sistema (ovvero associare le implementazioni definite con [Export] al contratto definito con [ImportMany].

private void _Compose()
{
  var c = new DirectoryCatalog(AppDomain.CurrentDomain.BaseDirectory);
  CompositionContainer container = new CompositionContainer(c);
  container.ComposeParts(this);
}

Nel main possiamo quindi utilizzare il servizio:

static void Main(string[] args)
{
  Program p = new Program();
  try
  {
    p._Compose();
  }
  catch (Exception ex)
  {
    System.Console.WriteLine(ex.Message);
  }

  if (p.NewsService == null)
  {
    System.Console.WriteLine("MEF non configurato correttamente.");
    System.Console.Read();
    return;
  }

  foreach (INewsService service in p.NewsService)
  {
    System.Console.WriteLine("Notizie {0}", service.Source);
    DateTime day = DateTime.Today;
    Array.ForEach(service.NewsOf(day),
            news => System.Console.WriteLine("{0} - {1}", 
                      day.ToShortDateString(), news));
  }
  System.Console.Read();
}

A questo punto possiamo definire altri plug-in e sarà sufficiente caricare gli assembly nella directory dell'applicazione per poterli eseguire.

namespace Gazzetta
{
    using System;
    // namespace di MEF
    using System.ComponentModel.Composition;
    using MEF.PluginInterface;

    [Export(typeof(INewsService))]
    public class GazzettaNewsService : INewsService
    {
        public string Source {
            get { return "Gazzetta"; }
        }

        public string[] NewsOf(DateTime day)
        {
            return new string[] 
            { 
                "Inter e Milan qualificate agli ottavi."
            };
        }
    }
}

Riferimenti:


Community Meeting: 1nn0va presenta gli AntiPatterns, i vizi del programmatore

Venerdì 26 novembre 2010 nuovo appuntamento con 1nn0va per un interessante meeting in due sessioni. Nella prima con il mio amico Marco scopriremo il linguaggio F#, cos'è, da dove nasce, come si scrive in F# e perchè tanti lo stanno apprezzando più di C#... Una sessione assolutamente da non perdere!
Nella seconda sessione avrò il piacere di mostrarvi le ultimissime novità dal mondo .NET. Vedremo come possiamo applicarle da subito per perdere quei vizi da programmatore che passano sotto il nome di AntiPatterns.

L'evento è gratuito e per partecipare potete iscrivervi direttamente da qui.


Refactoring: sostituire lo switch con il polimorfismo

Lo switch viene spesso utilizzato assieme ad un enumerativo per specificare porzioni di codice da eseguire in base al valore di una determinata variabile. L'utilizzo di tale costrutto rende però il nostro codice rigido e poco mantenibile perché all'aggiunta di un nuovo valore siamo costretti ad aggiornare sia l'enumerativo che lo switch.
Vediamo allora come con un refactoring object-oriented possiamo sostituire lo switch per rendere il nostro codice più flessibile, mantenibile e pulito.

Nell'esempio seguente abbiamo creato una classe MSOfficeLicence con un metodo Price che tramite uno switch ritorna il prezzo di una licenza Office in base al tipo (Home o Business):

public class MSOfficeLicence
{
  public enum LicenceType
  { 
   Home = 0,
   Business = 1
  }

  private MSOfficeLicence.LicenceType _type;
  public MSOfficeLicence.LicenceType Type { get { return _type; } }

  public MSOfficeLicence(MSOfficeLicence.LicenceType type)
  {
   this._type = type;
  }

  public decimal Price()
  {
   switch (_type)
   { 
     case LicenceType.Home:
       return (decimal)99.90;
     case LicenceType.Business:
       return (decimal)180.90;
     default:
       throw new ArgumentNullException("Type not valid");
   }
  }
}

Proviamo ad applicare il polimorfismo e quindi rendiamo la classe MSOfficeLicence e il metodo Price astratti e creiamo una classe derivata per ogni tipo di licenza:

public abstract class MSOfficeLicence
{
  public abstract decimal Price();
}

public class MSOfficeHome : MSOfficeLicence
{
  public override decimal Price()
  {
    return (decimal)99.90;
  }
}

public class MSOfficeBusiness : MSOfficeLicence
{
  public override decimal Price()
  {
    return (decimal)180.90;
  }
}

Ecco che tolto lo switch possiamo aggiungere nuovi tipi di licenza semplicemente creando una nuova derivata che esegue l'override del metodo Price. La logica del codice client deciderà quindi quale licenza istanziare magari tramite una factory o semplicemente tramite dependency injection:

MSOfficeLicence Licence = new MSOfficeHome();
Console.Write(Licence.Price());

Nota: I prezzi sono solo a titolo di esempio :-)