In un articolo precedente si è visto come sia semplice, con ASP.NET 2.0 e il suo approccio basato sul provider model, personalizzare molte funzionalità, come ad esempio l'API membership. La possibilità di estendere le API presenti - una cosa pressoché impossibile con le versioni 1.x senza doversi inventare trucchi più o meno complicati - permette di riscrivere pressoché ogni funzionalità di una web application con modifiche minime a fronte di cambiamenti anche significativi.
Ma se volessimo, a nostra volta, implementare il funzionamento a provider per nostre API e/o servizi o per notre esigenze specifiche, come dovremmo scrivere il codice relativo?
L'esempio
Ipotizziamo di dover scrivere un servizio che permetta di memorizzare le ricerche eseguite dagli utenti che accedono al motore di ricerca interno alla nostra web application. Non è particolarmente difficile scrivere il codice che permetta la memorizzazione delle parole ricercate: nella pagina che effettua la ricerca è sufficiente richiamare un'eventuale classe da noi scritta che memorizza e conteggia le parole chiave, memorizzandole in un database.
Nel nostro ipotetico esempio, supponiamo che inizialmente tale applicazione giri su un database Access per motivi di convenienza. Se in un secondo momento volessimo disporre di un database più performante come SQL Server o MySql, saremmo obbligati a riprendere in mano la nostra applicazione per il conteggio delle ricerche ed effettuare una serie di modifiche più o meno pesanti. E se invece volessimo utilizzare un file XML per memorizzare i dati?
Questi cambiamenti comporterebbero la modifica di molto codice; diversamente, se avessimo sviluppato la funzionalità sfruttando il modello a provider, sarebbe stato sufficiente scrivere un provider custom che memorizzasse le informazioni nel datastore desiderato per non dover modificare nient'altro. Di seguito vediamo l'approccio a tale problema con un esempio reale di sviluppo.
Inizio del progetto
Inizialmente dobbiamo decidere quali impostazioni configurabili dall'utente deve avere il servizio. Una impostazione di base comune a tutte le implementazioni potrebbe essere quella necessaria per indicare se i termini immessi per la ricerca debbano essere case sensitive. Le altre impostazioni per ogni provider si diversificano a seconda dei casi: per il provider che utilizza come datastore un database è necessario indicare la connectionString, ovvero la stringa di connessione al database o il nome del database utilizzato, per il provider che memorizza i dati in un file XML, dobbiamo includere la proprietà fileName, ovvero il nome del file dove vengono memorizzate le informazioni.
Ora che abbiamo deciso i passi preliminari, possiamo iniziare a scrivere il nostro servizio basato sui provider, che chiamiamo AzSearchProvider. Inizialmente dobbiamo definire una classe base che derivi direttamente o indirettamente dalla classe System.Configuration.ProviderBase. In essa indichiamo come abstract i metodi e le proprietà comuni a tutti i provider relativi alla nostra funzionalità.
using System; using System.Collections.Generic; using System.Text; using System.Configuration.Provider; public abstract class AzSearchProvider : ProviderBase { // Funzione standard public abstract string ApplicationName { get; set; } public abstract bool CaseSensitive { get; set; } public abstract int Viewed(string word); public abstract void Memorize(string word); }
Come accennato precedentemente, abbiamo definito una proprietà CaseSensitive, per impostare il fatto che caratteri maiuscoli e minuscoli siano considerati come diversi, e due metodi Viewed e Memorize; il primo ritorna il numero di volte nelle quali la parola passata come parametro è stata cercata, il secondo memorizza una nuova parola o incrementa il contatore delle ricerche per quelle già esistenti nel datastore.
Dato che è possibile creare più provider per AzSearchProvider, occorre innanzitutto creare una classe personalizzata che derivi da ProviderCollection per indicare nel file di configurazione l'elenco dei provider disponibili per la funzionalità in questione.
using System; using System.Collections.Generic; using System.Text; using System.Configuration.Provider; public class AzSearchProviderCollection : ProviderCollection { public new AzSearchProvider this[string name_provider] { get { return (AzSearchProvider)base[name_provider]; } } public override void Add(ProviderBase provider) { if (provider == null) throw new ArgumentNullException("provider"); if (!(provider is AzSearchProvider)) throw new ArgumentException("Invalid provider type", "provider"); base.Add(provider); } }
Oltre alla collezione, occorre definire anche la sezione di configurazione per la funzionalità. In questo caso dobbiamo creare un'altra classe che erediti direttamente dalla classe ConfigurationSection.
using System; using System.Configuration; public class AzSearchServiceSection: ConfigurationSection { [ConfigurationProperty("providers")] public ProviderSettingsCollection Providers { get { return (ProviderSettingsCollection)base["providers"]; } } [StringValidator(MinLength = 1)] [ConfigurationProperty("defaultProvider", DefaultValue = "AzSearchProvider")] public string DefaultProvider { get { return (string)base["defaultProvider"]; } set { base["defaultProvider"] = value; } } [ConfigurationProperty("caseSensitive", DefaultValue = true)] public bool CaseSensitive { get { return (bool)base["caseSensitive"]; } } }
Attenzione: Questo articolo contiene un allegato.
Commenti
Per inserire un commento, devi avere un account.
Fai il login e torna a questa pagina, oppure registrati alla nostra community.