Il modello basato sui provider è un aspetto molto importante di ASP.NET e rappresenta, da un punto di vista architetturale, una delle novità più interessanti della versione 2.0 del .Net Framework.
Il modello di provider permette agli sviluppatori sfruttare i provider nativi di ASP.NET oppure di sostituirli o migliorarli.
In questo articolo introduciamo il Modello di Provider spiegandone la motivazione di base, la struttura nel dettaglio e, sperimentando in modo diretto, la creazione di un provider di mappe di siti Web personalizzato che ci consente di estrapolare i dati relativi alle mappe dei siti da un database Ms Sql Server anziché da un file XML.
Perché utilizzare i provider?
L'utilizzo dei Provider nasce dalla necessità di disporre di un pattern semplice ed efficace per rendere alcune parti di una applicazione personalizzabili.
ASP .NET 2.0 prevede diversi servizi basati su provider, come ad esempio Membership, Ruoli, Gestione dello stato, Personalizzazione, Mappa e navigazione del sito ed altro; questi servizi utilizzano un API comune per svolgere le diverse operazioni. Questa API, facente parte del sistema di ASP.NET, viene esposta come componente collegabile (dll), in questo modo rimane incapsulata e gli sviluppatori possono utilizzarla senza preoccuparsi di come è strutturata internamente.
Se i provider inclusi nel sistema non sono sufficienti a soddisfare le proprie esigenze, ad esempio se si desidera archiviare i dati relativi allo stato delle sessioni in un database diverso da Ms SQL Server, è possibile implementare provider personalizzati in grado di comunicare con il tipo di database scelto. Il modello è facilmente estendibile, ciascun sviluppatore può implementare nuovi Provider personalizzati o acquistarli da terze parti.
Nel modello di Provider, l'API di livello superiore rimane la stessa mentre l'implementazione è affidata a specifiche classi "Provider"

Un pò di teoria: il design pattern
Dietro al modello di provider c'è il popolare design pattern comportamentale "pattern strategy" appartenente alla famiglia GoF (Gang of Four).
Il design pattern Strategy consiste nella possibilità di rendere intercambiabili tra loro le diverse strategie di implementazione di un algoritmo applicativo. Ogni applicazione, seleziona l'algoritmo più adatto in relazione al particolare contesto senza nessun impatto sull'interfaccia della funzionalità messa a disposizione dalla API di programmazione. Il tutto avviene in maniera del tutto trasparente agli sviluppatori.
Il pattern Strategy prevede, per ogni oggetto, un modo astratto di esporre le proprie funzionalità in modo tale che, un client, può scollegare l'implementazione di default e collegarne una propria.
Gli sviluppatori possono implementare nuovi Provider personalizzati, ridefinire il comportamento dei Provider già inclusi nel sistema, i client possono collegarsi e personalizzare comportamento e impostazioni.
Tutto questo non significa che l'applicazione diventa un progetto "open-source",
ma che è possibile personalizzare alcune parti dell'ambiente di runtime ASP.NET attraverso le classi denominate appunto provider, dalle quali è possibile derivarne una propria.
La pratica
L'implementazione di un proprio provider in ASP.NET prevede la scrittura:
- della classe
- del livello di configurazione
- del livello di memorizzazione
Per estendere un provider dobbiamo definire una nuova classe che eredita dalla classe base definita per quel provider. Tutte le classi base provider derivano da una classe base comune denominata Providerbase.
La classe Providerbase
fornisce il metodo Initialize()
che è l'unico metodo comune a tutti i provider.
Il file di configurazione, "web.config", contiene una sezione dedicata ai provider e, attraverso il metodo Initialize()
, le informazioni contenute in questa sezione vengono passate al metodo, cosi, ciascun provider le utilizza per inizializzare il proprio stato.
Modificare il SiteMapProvider
Come abbiamo detto, in ASP.NET i provider sono utilizzati per svolgere diversi compiti, nel nostro articolo prendiamo in considerazione il servizio di mappa del sito web e la relativa classe SiteMapProvider
, la classe base per la gestione delle informazioni della mappa del sito disponibile in ASP.NET.
La mappa di un sito web è una struttura dati gerarchica utilizzata per definire il layout di tutte le pagine dell'applicazione e la relazione che esiste tra le pagine. Il provider di mappa del sito per default, legge i dati relativi alla mappa, da un file XML, denominato web.sitemap
.
Nel nostro esempio, estendiamo il provider predefinito per ottenere un nuovo provider che recupera i dati relativi alla mappa, da un database Ms SQL Server anziché da un file XML e, infine, testeremo il provider.
Le classi derivate dalla classe base del provider SiteMapProvider dovranno creare un albero di oggetti nodo della mappa del sito.
Ciascun nodo contiene:
- nome
- url
- un genitore
- un elenco dei nodi figli
- i ruoli
XmlSiteMapProvider
Questo provider deriva dalla classe astratta StaticSiteMapProvider
SiteMapProvider
XmlSiteMapProvider
Listato 1. Le informazioni relative ai provider, nel web.config
<siteMap>
<providers>
<add name="XmlSiteMapProvider " siteMapFile="web.sitemap"
type="System.Web.XmlSiteMapProvider" />
</providers>
</siteMap>
Passiamo, ora, alla creazione del provider personalizzato che recupera i dati relativi alle mappe dei siti da un database Ms SQL Server.
Supponiamo di avere una tabella contenuta in un database SQL Server denominata SiteMap, ogni record della tabella rappresenta un nodo della mappa del sito. Per semplicità utilizziamo una sola tabella, contenente tre campi: Title, Url, Roles.
Figura 2. La tabella SiteMap in SQL Server
Creiamo una classe di provider di mappe dei siti personalizzati denominata MySiteMapProvider
, che consente di creare la mappa di un sito dai record memorizzati nella tabella SiteMap del database.
Apriamo la finestra "Esplora Soluzioni" utilizzando Visual Studio o VWD e aggiungiamo un nuovo elemento nella cartella "App_Code". Nella finestra di dialogo "Aggiungi nuovo elemento" selezioniamo Class come tipo di modello e nominiamo la classe "MySiteMapProvider.cs".
Figura 3. Aggiungere la classe al progetto
Importiamo nella nuova classe i namespaces che ci occorono.
Listato 2. I namespace
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Data.SqlClient;
using System.Collections.Specialized;
Nella dichiarazione della classe dobbiamo specificare che MySiteMapProvider
deriva da System.Web.StaticSiteMapProvider
.
Listato 3. Dichiarazione della classe
public class MySiteMapProvider : StaticSiteMapProvider
Aggiungiamo alcuni campi privati
.
Listato 4. I campi privati
public class MySiteMapProvider : StaticSiteMapProvider
{
static readonly string errore = "Manca la stringa di connessione";
private string strconn = null;
private SiteMapNode root = null;
Eseguiamo, ora l'override del metodo Initialize()
. Questo metodo inizializza le strutture dati da cui vengono prese le informazioni per la creazione della struttura del provider.
Listato 5. L'override del metodo Initialize
public override void Initialize (string name, NameValueCollection attributes)
{
base.Initialize (name, attributes);
if (attributes == null)
throw new ConfigurationException (errore);
strconn = attributes["connectionStringName"];
if (String.IsNullOrEmpty(strconn))
throw new ConfigurationException (errore);
}
Aggiungiamo alla classe il metodo BuildSiteMap()
di cui eseguiamo l'override. Questo metodo carica le informazioni per la Site Map dal database scelto.
Listato 6. Il Metodo BuildSiteMap
public override SiteMapNode BuildSiteMap ()
{
// Esco dal metodo se è stato già richiamato e il nodo root non è nullo
if (root != null)
return root;
// Creo il nodo root
root = new SiteMapNode (this, "Default.aspx", "Default.aspx", "Home");
AddNode(root, null);
// Eseguo la query per leggere i dati necessari per creare i nodi figli
SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["miaconn"].ConnectionString);
try {
connection.Open ();
SqlCommand command = new SqlCommand("SELECT Title, Url, Roles FROM SiteMap", connection);
SqlDataReader reader = command.ExecuteReader ();
int url = reader.GetOrdinal("Url");
int title = reader.GetOrdinal("Title");
int roles = reader.GetOrdinal("Roles");
// Aggiungo i nodi alla mappa del sito
while (reader.Read ()) {
SiteMapNode node = new SiteMapNode (this, reader.GetString(url), reader.GetString(url), reader.GetString(title));
if (!reader.IsDBNull (roles)) {
string rolenames = reader.GetString (roles);
if (!String.IsNullOrEmpty (rolenames)) {
string[] rolelist = rolenames.Split (new char[] { ',', ';' }, 512);
node.Roles = rolelist;
}
}
AddNode (node, root);
}
}
finally { connection.Close (); }
return root;
}
Aggiungiamo alla classe il metodo GetRootNodeCore()
. Questo metodo restituisce il nodo principale che gestisce tutti i sotto nodi e, permette, il caricamento della struttura presente nel provider.
Listato 7. Il Metodo GetRootNode()
protected override SiteMapNode GetRootNodeCore()
{
BuildSiteMap ();
return root;
}
Ora, per poter utilizzare il provider dobbiamo apportare delle modifiche al "web.config".Apriamo il file e ci assicuriamo di aver inserito e configurato in modo corretto la connessione al database.
Listato 8. La stringa di connessione al database
<connectionStrings>
<add name="miaconn"
connectionString="Data Source=.SQLEXPRESS;
AttachDbFilename=C:progettiwww.html.itWebProvidersApp_DataDatabase.mdf;
Integrated Security=True; User Instance=True"
providerName="System.Data.SqlClient" />
</connectionStrings>
All'interno della sezione <system.web>
del web.config, aggiungiamo il nostro provider nella sezione <siteMap>
e lo impostiamo come provider di default.
Listato 8. La sezione <siteMap> all'interno del web.config
<siteMap defaultProvider="MySiteMapProvider" enabled="true">
<providers>
<add name="MySiteMapProvider"
type="MySiteMapProvider" securityTrimmingEnabled="true"
connectionStringName="Database"/>
</providers>
</siteMap>
Passiamo ora, al test della nostra applicazione. Aggiungiamo al progetto una pagina e la chiamiamo "Default.aspx". Dalla "casella degli strumenti" trasciniamo nella pagina l'oggetto SiteMapDataSource
e l'oggetto TreeView
Figura 4. Creare la pagina per il test
Impostiamo quindi le proprietà dei due oggetti.
Listato 9. Le proprietà dei due oggetti
<form id="form1" runat="server">
<asp:SiteMapDataSource ID="siteMapDataSource" runat="server" />
<asp:TreeView ID="TreeView1" runat="server" DataSourceID="siteMapDataSource" />
</form>
Compiliamo ed eseguiamo l'applicazione. Apparirà la schermata con i dati della mappa del sito letti dalla tabella del database.
Figura 5. Risultato dell'esecuzione
Conclusioni
In questo articolo abbiamo prima introdotto il modello basato sui provider e poi abbiamo visto nel dettaglio, come creare un Site Map Provider personalizzato da utilizzare come provider di default per la creazione della struttura di navigazione del nostro sito web prelevando i dati da un database Ms SQL Server.
L'esempio vuole essere un punto di partenza per sperimentare questa tecnica nella personalizzazione dei vari provider inclusi nel sistema quando questi non risultano sufficienti a soddisfare le proprie esigenze.
Ti consigliamo anche