ASP.Net e Pattern Observer in Pratica – Quarta Parte

In questo post, come promesso in ASP.Net e Pattern Observer in Pratica – Terza Parte, utilizzeremo il pattern observer per assolvere al requisito prensentato nel primo post della serie ASP.Net e Pattern Observer in Pratica.
Allaciate le cinture che questa volta saremo un po’ lunghetti 🙂

Ricordiamo il Requisito

Implementazione di una pagina di ricerca dove sono presenti alcuni web user controls tra i quali uno in particolare si occupa di raccogliere l’input dell’utente per effettuare una ricerca tramite la pressione di un pulsante apposito (presente sullo stesso user control), l’operazione di ricerca deve in qualche modo essere notificata agli altri user controls presenti sulla stessa pagina che utilizzando gli stessi valori inseriti nel primo controllo dovranno filtrare e renderizzare i dati di dettaglio.

Ciò che implementeremo

Una serie di classi necessarie alla rappresentazione di un repository di Clienti, un unica pagina contenente due web user control uno per gestire l’operazione di ricerca (il pubblicatore) l’altro per la rappresentazione a video della lista filtrate di clienti (il sottoscrittore). Il controllo web che presenterà i dati filtrati riceverà da parte del controllo di ricerca una notifica ogni volta che l’utente modificherà i valori del filtro ed effettuerà una nuova ricerca. Insieme alla notifica viaggeranno anche i valori del filtro impostato da un controllo all’altro, il tutto senza scomodare in alcun modo la sessione.

Di seguito la screenshot dell’interfaccia web

DesignPattern - Esempio del pattern Observer

Per prima cosa andiamo a definire la classe “Customer”, che rappresenta il nostro modello

namespace DesingPattern.Sample.Observer.Model
{
    /// <summary>
    /// Rappresenta l'entità Cliente.
    /// </summary>
    public class Customer
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Surname { get; set; }
        public string City { get; set; }
    }
}

e la relativa “CustomerRepository” (che tramite alcuni metodi statici, vi ricordo che siamo in un esempio, ci fornirà la lista dei Clienti):

namespace DesingPattern.Sample.Observer.Data
{
    /// <summary>
    /// Rappresenta il repository per le entità Cliente.
    /// </summary>
    public class CustomerRepository
    {
        /// <summary>
        /// Restituisce la lista completa di tutti i Clienti.
        /// </summary>
        /// <returns></returns>
        public static IQueryable<Customer> GetAllCustomers()
        {
            List<Customer> customers = new List<Customer>();
            customers.Add(new Customer() { 
                Id = 1, 
                Surname = "Santaniello", 
                Name = "Ernesto", 
                City = "Napoli" 
            });
            customers.Add(new Customer() { 
                Id = 2, 
                Surname = "Tispo", 
                Name = "Armando", 
                City = "Napoli" 
            });
            // ecc..
            return customers.AsQueryable().OrderBy(c => c.Surname);
        }

        /// <summary>
        /// Restituisce una lista di clienti filtrata.
        /// </summary>
        /// <param name="filter">Rappresenta il filtro di ricerca.</param>
        /// <returns></returns>
        public static IQueryable<Customer> GetCustomers(CustomerFilter filter)
        {
            if (filter is NullCustomerFilter)
                return CustomerRepository.GetAllCustomers();

            if(filter.UseLikeFilter)
                return CustomerRepository.GetAllCustomers().Where(c =>
                        (string.IsNullOrEmpty(filter.Name) || c.Name.ToLower().Contains(filter.Name.ToLower()))
                        && (string.IsNullOrEmpty(filter.Surname) || c.Surname.ToLower().Contains(filter.Surname.ToLower()))
                        && (string.IsNullOrEmpty(filter.City) || c.City.ToLower().Contains(filter.City.ToLower()))
                    );
            else
                return CustomerRepository.GetAllCustomers().Where(c =>
                    (string.IsNullOrEmpty(filter.Name) || c.Name.Equals(filter.Name, StringComparison.OrdinalIgnoreCase))
                    && (string.IsNullOrEmpty(filter.Surname) || c.Surname.Equals(filter.Surname, StringComparison.OrdinalIgnoreCase))
                    && (string.IsNullOrEmpty(filter.City) || c.City.Equals(filter.City, StringComparison.OrdinalIgnoreCase))
                );
        }
    }
}

La classe “CustomerRepository” nel metodo “GetCustomers” accetta in ingresso un oggetto di tipo “CustomerFilter” (utilizzato per aggregare le informazioni di filtro) implementata come segue

namespace DesingPattern.Sample.Observer.Model
{
    /// <summary>
    /// Rappresenta il filtro di ricerca per i Clienti.
    /// </summary>
    public class CustomerFilter
    {
        public string Name { get; set; }
        public string Surname { get; set; }
        public string City { get; set; }
        public bool UseLikeFilter { get; set; }
    }

inoltre, utilizzando le nozioni alla base del pattern “NullObject” implementiamo anche la classe “NullCustomerFilter” che in questo caso si riduce ad essere una classe vuota che eredita da “CustomerFilter”

namespace DesingPattern.Sample.Observer.Model
{
    /// <summary>
    /// Rappresenta il filtro vuoto di ricerca per i Clienti.
    /// </summary>
    public class NullCustomerFilter : CustomerFilter
    {
    }
}

L’implementazione d’esempio del pattern observer l’abbiamo già vista, ma rispetto a quella dobbiamo aggiungere qualcosa che permetta ai sottoscrittori di ricevere dei dati durante la fase di notifica. A tale scopo modifichiamo la firma del metodo “Update” aggiungendo a questa un parametro in input (del tipo a noi necessario) così da poter passare le informazioni al sottoscrittore durante la chiamata al metodo “Notify” del pubblicatore:

Nota
E’ di estrema importanza comprendere che modificare la firma del metodo Update non vuol dire modificare la struttura del Pattern Observer, i pattern identificano il disegno della soluzione da implementare e non la loro esatta implementazione.

Se a questo punto siamo abbastanza furbi da utilizzare i generics possiamo costruire un interfaccia generica per qualsiasi tipo di sottoscrittore in questo modo:

namespace DesingPattern.Sample.Observer.Interfaces
{
    /// <summary>
    /// Interfaccia da implementare in tutti i sottoscrittori.
    /// </summary>
    public interface IObserver<T>
    {
        /// <summary>
        /// Aggiorna lo stato interno del sottoscrittore quando riceve 
        /// l'evento di notifica dal pubblicatore.
        /// </summary>
        /// <param name="data">Dati da passare durante la notifica.</param>
        void Update(T data);
    }
}

Nota
Attenzione a partire dalla versione 4.0 del Framework .Net l’interfaccia <a title="Interfaccia System.IObserver” href=”http://msdn.microsoft.com/it-it/library/dd783449(v=vs.100).aspx” target=”_blank”>IObserver<T> è già presente all’interno del namespace System quindi attenti agli using.

Allo stesso modo, sempre utilizzando i generics, modificheremo l’interfaccia ISubject come segue:

namespace DesingPattern.Sample.Observer.Interfaces
{
    /// <summary>
    /// Interfaccia da implementare sul pubblicatore.
    /// </summary>
    interface ISubject<T>
    {
        /// <summary>
        /// Registra un sottoscrittore all'evento di notifica. 
        /// </summary>
        /// <param name="o">Interfaccia che identifica un Sottoscrittore.</param>
        void Attach(IObserver<T> o);

        /// <summary>
        /// Rimuove un sottoscrittore dall'evento di notifica.
        /// </summary>
        /// <param name="o">Interfaccia che identifica un Sottoscrittore.</param>
        void Detach(IObserver<T> o);

        /// <summary>
        /// Notifica a tutti i sottoscrittori il cambio di stato.
        /// </summary>
        void Notify();
    }
}

A questo punto andiamo ad implementare una classe astratta che rappresenti la versione base del controllo web di ricerca che erediti da System.Web.UI.Usercontrol

namespace DesingPattern.Sample.Observer.WebUserControls
{
    /// <summary>
    /// Controllo di filtro base.
    /// </summary>
    /// <typeparam name="T">Tipo di filtro.</typeparam>
    public abstract class FilterControlBase<T> : System.Web.UI.UserControl, Interfaces.ISubject<T>
    {
        private T _filter;
        /// <summary>
        /// Lista interna degli sottoscrittori registrati all'evento di notifica.
        /// </summary>
        private List<Interfaces.IObserver<T>> _observers = new List<Interfaces.IObserver<T>>();

        /// <summary>
        /// Restituisce o imposta il valore del filtro.
        /// </summary>
        public T Filter
        {
            get { return _filter; }
            set
            {
                _filter = value;
                // Ogni volta che il valore del filtro cambia
                // viene spedita la notifica ai sottoscrittori.
                this.Notify();
            }
        }

        /// <summary>
        /// Sottoscrive un osservatore. 
        /// </summary>
        /// <param name="o">Riferimento al sottoscrittore.</param>
        public void Attach(Interfaces.IObserver<T> o)
        {
            _observers.Add(o);
        }

        /// <summary>
        /// Rimuove un osservatore.
        /// </summary>
        /// <param name="o">Riferimento al sottoscrittore</param>
        public void Detach(Interfaces.IObserver<T> o)
        {
            _observers.Remove(o);
        }

        /// <summary>
        /// Notifica, a tutti gli osservatori sottoscritti, 
        /// che il valore del filtro è stato modificato.
        /// </summary>
        public void Notify()
        {
            foreach (Interfaces.IObserver<T> o in _observers)
            {
                o.Update(this.Filter);
            }
        }
    }
}

La cose da notare nell’implementazione della classe “FilterControlBase” sono:

  1. La presenza della proporty “Filter” tipizzata tramite i generics;
  2. Il Setter della property “Filter” che invoca il metodo “Notify” ogni volta che viene cambiato lo stato del filtro;
  3. Nel metodo “Notify” a tutti i sottoscrittori viene notificato il valore del nuovo filtro.

Ormai ci siamo, le ultime cose di cui abbiamo bisogno sono i due web user control e la pagina che li ospiterà.

Il controllo Search.ascx

Il controllo Search.ascx identifica il nostro pubblicatore.
Nel markup inseriamo una serie di controlli per la raccolta dell’input utente e due pulsanti uno per effettuare la ricerca l’altro per ripulire la form.

<%@ Control Language="C#" 
    AutoEventWireup="true" 
    CodeBehind="Search.ascx.cs" 
    Inherits="DesingPattern.Sample.Observer.WebUserControls.Search" %>

<fieldset id="search">
    <legend>Search Fields</legend>
    <asp:CheckBox ID="chkUseLikeFilter" runat="server" /> Use Like Mode
    <div class="filters break">
        <div class="field">
            <asp:Label ID="lblSurname" runat="server" 
                       AssociatedControlID="txtSurname" Text="Surname" />
            <asp:TextBox ID="txtSurname" runat="server" />
        </div>
        <div class="field">
            <asp:Label ID="lblName" runat="server" 
                       AssociatedControlID="txtName" Text="Name" />
            <asp:TextBox ID="txtName" runat="server" />
        </div>
        <div class="field">
            <asp:Label ID="lblCity" runat="server" 
                       AssociatedControlID="txtCity" Text="City" />
            <asp:TextBox ID="txtCity" runat="server" />
        </div>
        <div class="buttons break">
            <asp:Button ID="btnApplyFilter" runat="server" 
                        Text="Apply Filter" OnClick="btnApplyFilter_Click" />
            <asp:Button ID="btnClearFilter" runat="server" 
                        Text="Clear Filter" OnClick="btnClearFilter_Click" />
        </div>
    </div>
</fieldset>

Il codice del controllo contiene i soli gestori d’evento dei due pulsanti dove vengono reimpostati i filtri. Inoltre ereditando dalla classe astratta “FilterControlBase” nel momento in cui viene reimpostata la property “Filter” viengono anche automaticamente notificati ai sottoscrittori i nuovi valori di filtro.

namespace DesingPattern.Sample.Observer.WebUserControls
{
    public partial class Search : WebUserControls.FilterControlBase<CustomerFilter>
    {
        protected void btnApplyFilter_Click(object sender, EventArgs e)
        {
            // Alla pressione del pulsante di ricerca sul controllo basterà 
            // aggiornare il valore del filtro intrinsecamente legato al pubblicatore.
            this.Filter = new CustomerFilter() { 
                UseLikeFilter = chkUseLikeFilter.Checked,
                Surname = txtSurname.Text,
                Name = txtName.Text,
                City = txtCity.Text
            };
        }

        protected void btnClearFilter_Click(object sender, EventArgs e)
        {
            // Alla pressione del pulsante Clear sul controllo basterà 
            // aggiornare il valore del filtro intrinsecamente legato al pubblicatore.
            this.Filter = new NullCustomerFilter();

            // Ripuliamo inoltre i controlli di input
            chkUseLikeFilter.Checked = false;
            txtSurname.Text = string.Empty;
            txtName.Text = string.Empty;
            txtCity.Text = string.Empty;
        }
    }
}

Il controllo SearchResults.ascx

Il controllo SearchResults.ascx identifica invece il nostro sottoscrittore.
Nella parte di marckup inseriamo un semplice repeater, come segue

<%@ Control Language="C#" 
    AutoEventWireup="true" 
    CodeBehind="SearchResults.ascx.cs" 
    Inherits="DesingPattern.Sample.Observer.WebUserControls.SearchResults" %>

<asp:Repeater ID="rptResults" runat="server">
    <HeaderTemplate>
        <table>
            <thead>
                <tr>
                    <th>ID</th>
                    <th>Surname</th>
                    <th>Name</th>
                    <th>City</th>
                </tr>
            </thead>
            <tbody>
    </HeaderTemplate>
    <ItemTemplate>
        <tr>
            <td><%#Eval("Id")%></td>
            <td><%#Eval("Surname")%></td>
            <td><%#Eval("Name")%></td>
            <td><%#Eval("City")%></td>
        </tr>
    </ItemTemplate>
    <FooterTemplate>
            </tbody>
        </table>
    </FooterTemplate>
</asp:Repeater>

mentre nella parte di codice inseriamo

  1. Il gestore di evento relativo al Load del controllo, che si occuperà di bindare la lista dei clienti al repeater durante il primo caricamento (ovvero quando la pagina viene caricata per la prima volta ed il filtro non è stato ancora impostato);
  2. Il metodo Update, relativo all’implementazione dell’interfaccia “Interfaces.IObserver” (che viene invocato dal publicatore durante l’esecuzione del metodo “Notify”) nel quale viene filtrata la lista dei clienti in base ai valori di filtro passati durante la notifica del pubblicatore.
namespace DesingPattern.Sample.Observer.WebUserControls
{
    public partial class SearchResults : System.Web.UI.UserControl, 
                                         Interfaces.IObserver<CustomerFilter>
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!IsPostBack)
            {
                // Binda i dati non filtrati sul repeater per la prima visualizzazione.
                rptResults.DataSource = CustomerRepository.GetAllCustomers();
                rptResults.DataBind();
            }
        }

        public void Update(CustomerFilter data)
        {
            // Binda i dati filtrati sul repeater.
            rptResults.DataSource = CustomerRepository.GetCustomers(data);
            rptResults.DataBind();
        }
    }
}

La pagina web contenitore

In fine nella pagina Default.aspx inseriamo i due web controls

<%@ Page Language="C#" AutoEventWireup="true" 
         CodeBehind="Default.aspx.cs" 
         Inherits="DesingPattern.Sample.Observer.Default" %>
<%@ Register src="WebUserControls/Search.ascx" 
             tagname="Search" tagprefix="uc" %>
<%@ Register src="WebUserControls/SearchResults.ascx" 
             TagName="SearchResults" tagprefix="uc" %>

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>ASP.Net &amp; Pattern Observer in Practice</title>
</head>
<body>
    <form id="form1" runat="server">
        <h1>ASP.Net &amp; Pattern Observer in Practice</h1>
        <uc:Search ID="ucSearch" runat="server" />
        <uc:SearchResults ID="ucSearchResults" runat="server" />
    </form>
</body>
</html>

e nel code-behind registriamo il sottoscrittore alla notifica nel gestore d’evento “Init” della pagina

namespace DesingPattern.Sample.Observer
{
    public partial class Default : System.Web.UI.Page
    {
        protected void Page_Init(object sender, EventArgs e)
        {
            // Registra il componente "ucSearchResults" alla notifica.
            ucSearch.Attach(ucSearchResults);
        }
    }
}

Bene se hai resistito fino a questo punto ti meriti di scaricare il progetto di esempio, ma prima di lasciarti voglio aggiungere ancora uno spunto..

Immagina che, nell’esempio implementato dopo l’operazione di ricerca, effettuando un click su una delle righe presenti nella griglia dei clienti tu debba visualizzare un dettaglio più corposo dei dati relativi al cliente selezionato… 😉
Chi vieta che un sottoscrittore (in questo caso SearchResults.ascx) sia contemporaneamente anche un pubblicaotore?

Sperando di averti stuzzicato abbasanza ti lascio come esercizio questo unltimo punto, ormai dovresti essere perfettamente a tuo agio con il pattern observer!!!

ASP.Net e Pattern Observer in Pratica – Prima Parte

Ieri mi è stata chiesta una piccola consulenza relativamente ad un bug presente su una pagina web sviluppata in ASP.Net Web Forms e vorrei condividere con voi sia lo scenario sia la soluzione implementata così da approfittare per parlare del Pattern Observer.

Il Requisito

Implementazione di una pagina di ricerca dove sono presenti alcuni web user controls tra i quali uno in particolare si occupa di raccogliere l’input dell’utente per effettuare una ricerca tramite la pressione di un pulsante apposito (presente sullo stesso user control), l’operazione di ricerca deve in qualche modo essere notificata agli altri user controls presenti sulla stessa pagina che utilizzando gli stessi valori inseriti nel primo controllo dovranno filtrare e renderizzare i dati di dettaglio.

La Soluzione originariamente implementata

La soluzione originariamente implementata, ovvero quella che generava bug, lavorava più o meno così:

  • Creazione di 3 user control
    • Ricerca.ascx
    • ListaDettagli.ascx
    • Dettaglio.ascx
  • L’utente inputa una serie di valori (tramite TextBox, CheckBox, ed altri controlli… presenti nel controllo Ricerca.ascx);
  • L’utente Clicca sul pulsante “Cerca” (sempre presente nel controllo Ricerca.ascx);
  • L’user control nel gestore di evento associato al click del bottone “cerca” istanzia un oggetto preposto con tutte le informazioni inserite dall’utente e lo memorizza in sessione;
  • Nell’evento Load degli altri user control viene letto l’oggetto in sessione e se questo non è null allora viene utilizzato come filtro.

Le problematiche riscontrate

Quello che il cliente lamenta è che la ricerca funziona a singhiozzi… ovvero:

  • La prima ricerca non funziona mai;
  • La seconda ricerca funziona se non vengono cambiati i dati inputati per la ricerca;
  • Le seguenti ricerche filtrano i dati dei dettagli con i dati inputati dall’utente per la ricerca precedente.

..ma come mai? ..e soprattutto sono solo questi i problemi effettivamente portati dalla soluzione implementata? ..oppure ce ne sono altri che l’utente (o addirittura il pogrammatore) non sta considerando? Inoltre qual’è il grado di portabilità e/o di estensione delle componenti software sviluppate?

La motivazione del problema ed una soluzione apparente

La motivazione del problema è molto semplice, nel ciclo di vita di una pagina ASP.Net  l’evento Postback viene scatenato dopo l’evento Load, quindi quando i controlli di dettaglio leggono il valore dalla sessione (nell’evento Load) lo leggono prima che l’user control Ricerca.ascx lo inserisca in sessione durante il Postback!

A questo punto, individuata l’origine del comportamento anomalo, potremmo essere portati a pensare che posticipare la lettura dei dati della sessione in un evento successivo al Postback (per esempio il PreRender) risolva il problema… bè diciamo che l’anomalia relativa alla ricerca effetivamente scompare ma questa è veramente una soluzione? ..oppure è quella che più comunemente  nel nostro campo viene definita come una pezza su un’implementazione poco controllabile?

Mi spiace dire che purtroppo siamo nel secondo caso…

..e allora cerchiamo di capire insieme come i design pattern possano aiutarci nell’implementare una soluzione più elegante ed affidabile, vediamo a cosa serve e come implementare il pattern observer.

Disabilitare le zone di Orchard per la gestione dei Widgets

Nei vari Content management system presenti sul mercato, c’è sempre in qualche modo la possibilità di specificare nel layout del sito in costruzione alcune zone che possono essere utilizzate per inserire dinamicamente dei widgets dal pannello di amministrazione del CMS stesso.

In  WordPress, per esempio, le zone nelle quali si possono inserire i widgets all’interno della struttura di un tema si chiamano sidebar e sono registrabili in un file chiamato functions.php tramite la seguente funzione:

   <?php $args = array(
      'name'          => __( 'Sidebar name', 'theme_text_domain' ),
      'id'            => 'unique-sidebar-id',
      'description'   => '',
      'class'         => '',
      'before_widget' => '<li id="%1$s" class="widget %2$s">',
      'after_widget'  => '</li>',
      'before_title'  => '<h2 class="widgettitle">',
      'after_title'   => '</h2>' ); 
   ?>

Quando ho sviluppato Mango Theme, il mio primo tema per Orchard, ho deciso di non utilizzare tutte e 20 le zone rese disponibili dal tema installato di default (TheThemeMachine) e devo essere sincero ho storto un pò il naso sul fatto che credevo di non avere alcun modo, a parte la Theme Zone Preview, per poter notificare all’utente che alcune zone non erano viualizzabili con il mio tema.

Mi sono chiesto, forse per troppo tempo: “possibile che con una gestione così arguta dei layer non abbiano previsto un modo per risolvere la questione senza implementare qualche sporco workaround?”

Così, ultimamete, ripresentatomi nuovamente il problema, ho chiesto direttamente sul forum di Orchard. Bè la soluzione non solo è Semplice ma soprattutto è molto Elegante.

Infatti direttamente all’interno del file Manifest presente nella cartella del tema (con il nome di Theme.txt) è possibile tra le altre cose specificare quali sono le zone abilitate, ecco un esempio (che nello specifico riporta le 20 zone del tema TheMetroTheme del quale è disponibe anche il codice sorgente):

Name: The Metro Theme
Version: 0.5.0
Author: Marco Siniscalco
Tags: responsive, modern, modern iu, metro, metrostyle
Description: The Metro Theme is a clean and flexible multi-zone theme. It features 20 collapsible widget zones and is flexible enough to cover a wide range of layouts.
Website: http://orchardmetrotheme.codeplex.com/
Zones: Header, Navigation, Featured, BeforeMain, AsideFirst, Messages, BeforeContent, Content, AfterContent, AsideSecond, AfterMain, TripelFirst, TripelSecond, TripelThird, FooterQuadFirst, FooterQuadSecond, FooterQuadThird, FooterQuadFourth, Footer

vi mostro cosa, con la configurazione sovrastante, ritroviamo nell’area di amministrazione dei widgets

Orchard Active-Widgets-Zones

ma se avessimo scritto

Name: The Metro Theme
Version: 0.5.0
Author: Marco Siniscalco
Tags: responsive, modern, modern iu, metro, metrostyle
Description: The Metro Theme is a clean and flexible multi-zone theme. It features 20 collapsible widget zones and is flexible enough to cover a wide range of layouts.
Website: http://orchardmetrotheme.codeplex.com/
Zones: Header, Navigation, Content, Footer

avremmo avuto

Customize Orchard Active Widgets Zones

Ma attenzione!
Non è possibile solo disabilitare le zone che non gestiamo ma volendo anche aggiungerne di nuove!

Vi rimando quindi alla pagina della documentazione ufficiale di Orchad con la lista di tutte le voci utilizzabili all’interno dei file manifest di moduli e temi.

Metro Theme for Orchard CMS – Novità

Solo due giorni fa scrivevo due righe per notificare ai passanti che da qualche giorno, nel tempo libero, sto viluppando un tema per Orchard e che per ovvie motivazioni ho battezzato con il nome di  Metro Theme for Orchard

Ma tutto mi aspettavo tranne di arrivare in questi ultimi 2 giorni a rifattorizzare tutti i CSS con l’intento di migliorare la resa grafica e la navigabilità su diverse tipologie di dispositivi (tablet, smartphone, desktop, ecc…).

Che non si urli al miracolo, sia chiaro! 😀
..un lungo lavoro mi attende, dopo tutto il progetto ha solo una settimana di vita!

Comunque per il momento chi vuole può recarsi sul sito del progetto e scaricare i sorgenti per vedere il tema all’opera, sempre considerando che si tratta di una versione mooolto Alpha!

Ed ecco le nuove screenshoot del sito d’esempio che sto preparando e che appena terminato sarà scaricabile, come già fatto per il tema Mango Theme.

Metro Theme for Orchard - Light Blue

Metro Theme for Orchard - Dark Green

Metro Theme for Orchard CMS

Un bel po’ di tempo fa ho sviluppato un tema dallo stile “vagamente” Windows Phone per Orchard CMS che potete trovare in rete con tanto di codice sorgente utilizzando la keywords Mango Theme (o più semplicemente cliccando sui link che vi ho lasciato).

Bene! Bravo Marco anche tu hai dato il tuo piccolo contributo al mondo dell’open source!

Questo era quello che pensavo fino a un po’ di tempo fa.. ma visto che non so mai tenere la bocca chiusa mi sono lasciato scappare in una discussione su un forum la notizia che di tanto in tando mi solleticava l’idea di sviluppare un tema in stile Metro Style (e si al tempo si chiamava ancora così) magari con qualche possibilità di personalizzazione in quanto ai colori, ecc..

Signori e signori parafrasando un’antica sentenza medievale oggi affermo che “ogni promessa è debito” ed io sono un uomo di parola… così questa notte invece di dormire sono qui ad uploadare su codeplex.com i sorgenti della versione 0.5 ancora in Alpha del tema “promesso” anche se la strada per una prima versione finale è ancora lontanuccia…

Per i più curiosi vi lascio alcune screenshot

Ecco il tema nella versione Light + Accent Color Blue

Metro Theme Orchard Blue - Home

mentre qui invece lo vediamo nella versione Dark + Accent Color Green con una panoramica sui principali stili tipografici attualmente disponibili

Metro Theme Orchard Dark Green

Inoltre visto che relativamente a Mango Theme mi è stato chiesto più volte di avere la possibilità di personalizzare alcune caratteristiche del tema direttamente dal pannello amministrativo di Orchard l’attuale view per la personalizzazione del tema

Metro Theme Settings

Bene, speriamo quindi di avere presto una prima versione finale!!! (ricordo che è gradito qualsiasi tipo di input, critica e/o consiglio (magari direttamente nel forum sul sito del progetto).

Bye! 😉

Disponibile Orchard 1.6

Da qualche giorno è disponibile ufficialmente la versione 1.6 di Orchard il CMS open source targato Microsoft.

Tra le novità più interessanti troviamo sicuramente:

  • Aggiornamento ad ASP.NET MVC 4 ed a Razor v2
  • Introdotto il supporto all’utilizzo delle Web API
  • Supporto a MySQL
  • SysCache per un’implementazione di default di un database cache provider
  • Netto miglioramento delle performance
  • Precompiled target: nuova modalità di build per distribuzioni senza codici sorgenti.
  • Estesa la configurazione delle sessioni ai moduli e per route.
  • Più di 200 i bug corretti

Sicuramente non si può negare che versione dopo versione Orchard ci offra una sempre crescente quantità di features interessanti.

Personalmente trovo particolarmente interessante il supporto alle Web API per la possibilità di sviluppare moduli che espongano le proprie funzionalità come API pubbliche!

Certo c’è da dire che con tutto questo “sfoggio” di ultime tecnologie non sarà facile (ovviamente questo è un eufemismo) trovare un hosting italiano che supporti il prodotto… ah… il bel paese!!! ma questo ovviamente è un problema che ritroviamo a prescindere dall’utilizzo del CMS in questione!

Ma ecco arrivato il momento dei consigli per gli acquisti!!! 😀 vorrei infatti pubblicizzare la neonata Community Italiana dedicata ad Orchard alla quale spero presto di poter offrire un po’ del mio tempo ma un link è pur sempre un buon inizio no?

E tu? Cosa ne pensi di Orchard?

MVC Web Api e IHttpControllerActivator Dependency Injection

In questi giorni sto lavorando ad un progetto interessante che prevede un massiccio uso di ASP.NET Web API.
Così, come ormai ad ogni startup di progetto, ci prepariamo ad architettare quel qualcosa 🙂 che ci permetta di iniettare dove necessario le giuste dipendenze allo scopo di semplificare la fase di test dei prodotti finali delle nostre svariate elucubrazioni mentali 😀 …

Dopo una serie di considerazioni fatte, sulle quali non mi dilungherò,  decidiamo di utilizzare MS Unity come IoC Container e ci lanciamo nell’ormai classica implementazione di un ControllerFactory per intercettare la creazione dei Controller per l’applicazione ASP.NET MVC4 come segue

public class UnityControllerFactory : DefaultControllerFactory
{
    private readonly IUnityContainer _container;

    /// <summary>
    /// Base Constructor
    /// </summary>
    ///Instance of Container.
    public UnityControllerFactory(IUnityContainer container)
    {
        _container = container;
    }

    /// <summary>
    /// Returns a valorized instance of the container.
    /// </summary>
    /// <param name="requestContext">Information about HTTP Request.</param>
    /// <param name="controllerType">Controller Type.</param>
    /// <returns></returns>
    protected override IController GetControllerInstance(RequestContext requestContext,
                                                         Type controllerType)
    {
        Contract.Requires(requestContext != null, "requestContext");
        Contract.Requires(controllerType != null, "controllerType");

        return _container.Resolve(controllerType) as IController;
    }

    /* Ulteriori override di nostra necessità...
     * protected override ...
     * {
     *    ...
     * }
    */
}

Nulla di nuovo quindi e procediamo a registrare il nostro container nel global.asax

public class WebApiApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();

        WebApiConfig.Register(GlobalConfiguration.Configuration);
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);

        var container = this.GetContainer("unity");
        var unityControllerFactory = new UnityControllerFactory(container);
        ControllerBuilder.Current.SetControllerFactory(unityControllerFactory);
    }

    public IUnityContainer GetContainer(string name)
    {
        IUnityContainer container = new UnityContainer();

        object section = ConfigurationManager.GetSection(name);
        if (section == null)
            throw new InvalidOperationException("No unity configuration was found, could not instansiate container");

        UnityConfigurationSection unityConfigurationSection = section as UnityConfigurationSection;
        unityConfigurationSection.Configure(container);

        return container; 
    }
         
}

Ma purtroppo ci rendiamo subito conto che l’implementazione del nostro UnityControllerFactory non ci permette di intercettare la creazione degli ApiCotroller e di conseguenza neanche di iniettare le nostre dipendenze in questi ultimi… la soluzione?

Abbiamo bisogno di un UnityHttpControllerActivator (per ulteriori informazioni leggi qui)

Poche righe ancora quindi per intercettare la creazione i nostri WebApiController

public class UnityHttpControllerActivator : IHttpControllerActivator
{
    private readonly IUnityContainer _container;
    private readonly DefaultHttpControllerActivator _defaultActivator;

    public UnityHttpControllerActivator(IUnityContainer container)
    {
        _container = container;
        _defaultActivator = new DefaultHttpControllerActivator();
    }

    public IHttpController Create(System.Net.Http.HttpRequestMessage request, 
                                  HttpControllerDescriptor controllerDescriptor, 
                                  Type controllerType)
    {
        IHttpController httpController = _container.Resolve(controllerType) as IHttpController;
        if (httpController != null)
        {
            return _container.Resolve(controllerType) as IHttpController;
        }
        else
        {
            return _defaultActivator.Create(request, controllerDescriptor, controllerType);
        }
    }
}

a questo punto dobbiamo aggiungere alla funzione Application_Start nel global.asax

public class WebApiApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();

        WebApiConfig.Register(GlobalConfiguration.Configuration);
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);

        var container = this.GetContainer("unity");
        var unityControllerFactory = new UnityControllerFactory(container);
        ControllerBuilder.Current.SetControllerFactory(unityControllerFactory);

        var unityHttpControllerActivator = new UnityHttpControllerActivator(container);
        GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerActivator), 
                                                           unityHttpControllerActivator);
    }
    
    ...
}

Bene! ..ed ora iniettate tutte le dipendenze di cui avete bisogno e buon lavoro! 😀