asp - asp.net - aspcode.it

COMMUNITY - Login
 Username:
 
 Password:
 
Voglio registrarmi!
Password dimenticata?
 Utenti on-line: 0
 Ospiti on-line: 5921
ASPCode.it - Store

  > > Articoli

Creazione di configuration section personalizzate

Data di pubblicazione: 18/10/2005        Voto della community: 0,00 (Votanti: 0)

Tutti i programmatori .NET, penso, hanno a che fare ogni giorno con file di configurazione (.config) per gestire al meglio le proprie applicazioni web o windows.
In applicazioni ASP.NET soprattutto, l'uso del web.config è quasi obbligatorio. Tale file permette infatti sia di settare opzioni per tutte le pagine del sito (come il tipo di autenticazione utilizzata o le opzioni di gestione della sessione), sia di archiviare dei valori user-defined, definiti da coppie chiave-valore, utili al programmatore in ogni pagina del proprio progetto; un esempio di questo tipo di valori sono sicuramente le opzioni di connessione al database. Queste coppie chiave-valore vengono inserite definendo l'elemento appSettings in questo modo:

<appSettings>
  <add key="miaChiave" value="mioValore" />
</appSettings>

N.B.: l'elemento appSettings va inserito all'interno dell'elemento "configuration".

Nelle pagine di code-behind, il valore definito dal web.config, può essere prelevato attraverso l'uso delle classi del namespace System.Configuration.

string myVal = ConfigurationSettings.AppSettings["miaChiave"];

Ma se avessimo bisogno di archiviare più di un valore per una stessa chiave? Oppure se le nostre applicazioni necessitano di file di configurazione personalizzati secondo quelle che possono essere le scelte implementative pensate in fase di progettazione?
In questi casi ci viene in aiuto il .NET Framework, che allinterno del namespace System.Configuration ha definite 4 classi per creare sezioni personalizzate all'interno dei propri file .config:
  • DictionarySectionHandler - Classe che legge coppie chiave-valore.
  • IgnoreSectionHandler - Classe che permette di ignorare altri tipi di sezioni.
  • NameValueSectionHandler - Classe che legge coppire nome-valore.
  • SingleTagSectionHandler - Classe che permette di definire un elemento di configurazione cui assegnare più attributi chiave-valore.
Ogni custom section va prima definita inserendo un elemento "section" all'interno dell'elemento "configSections", speficandone il nome da utilizzare e il tipo. Ecco un esempio d'uso di questi tipi di sezioni:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="MyNameValueSection"
       type="System.Configuration.NameValueSectionHandler" />
    <section name="MyDictionarySection"
       type="System.Configuration.DictionarySectionHandler" />  
    <section name="singleSection"
      type="System.Configuration.SingleTagSectionHandler" />
  </configSections>

  <MyNameValueSection>
    <add key="item1" value="item1" />
    <add key="item2" value="item2" />
  </MyNameValueSection>

  <MyDictionarySection>
    <add key="item1" value="item1" />
    <add key="item2" value="item2" />
  </MyDictionarySection>

  <singleSection item1="value1" item2="value2" item3="value3" />
  
</configuration>

Per prelevare i valori delle sezioni inserite nel file .config utilizziamo il metodo GetConfig() della classe ConfigurationSettings. Questo metodo prende come parametro il nome della sezione personalizzata (attributo "name" dell'elemento "section") e ritorna un object generico; a questo oggetto va però fatto un casting a seconda del tipo di section handler utilizzato.
Nel caso della classe NameValueSectionHandler, va fatto un casting con la classe NameValueCollection.

NameValueCollection coll = (NameValueCollection)ConfigurationSettings.GetConfig("MyNameValueSection");
Console.WriteLine(coll["item1"]);

Negli altri due casi, quindi per le sezioni di tipo DictionarySectionHandler e SingleTagSectionHandler, è possibile sia fare un casting con un oggetto di tipo Hashtable, sia con un oggetto di tipo IDictionary.

IDictionary tableD = (IDictionary)ConfigurationSettings.GetConfig("MyDictionarySection");
Console.WriteLine(tableD["item1"]);

Hashtable hash = (Hashtable)ConfigurationSettings.GetConfig("MyDictionarySection");
IDictionaryEnumerator myEnumerator = hash.GetEnumerator();
while(myEnumerator.MoveNext())
{
  Console.WriteLine(myEnumerator.Key+": "+myEnumerator.Value);
}

Tutte le 4 classi appena descritte implementano l'interfaccia IConfigurationSectionHandler. Questa interfaccia espone un unico metodo, il metodo Create, che dovrà contenere il codice utilie ad effettuare il parsing della sintassi XML della relativa sezione. Implementando questa interfaccia abbiamo quindi la possibilità di creare delle sezioni di configurazione personalizzate, potendo decidere completamente la sintassi XML che le caratterizza, in modo tale da farle corrispondere ai requisiti richiesti dalle nostre applicazioni.
Vediamo quindi un esempio su come creare una custom section, che contenga le voci di un ipotetico menu per le pagine di un sito web. Questa è la sezione personalizzata a cui vogliamo arrivare:

<configSections>
  <section name="MenuItemSettings"
     type="Peppe.Configuration.MenuConfigurator, Peppe.Configuration"/>
</configSections>

<MenuItemSettings type="Peppe.Configuration.MenuItemSettings, Peppe.Configuration">
  <MenuItems>
    <MenuItem DisplayName="Home page"
        Href="http://www.peppedotnet.it"
        Target="_self" />

    <MenuItem DisplayName="Blog"
        Href="http://www.peppedotnet.it/Blog"
        Target="_self" />

    <MenuItem DisplayName="Articoli"
        Href="http://www.peppedotnet.it/Articoli"
        Target="_self" />
  </MenuItems>
</MenuItemSettings>

Prima di tutto creiamo la classe MenuItem, contenente le tre proprietà DisplayName, Href e Target con i relativi modificatori get e set. Poi creiamo la collezione MenuItemCollection (derivata dalla classe CollectionBase), collezione di oggetti di tipo MenuItem utile ad archiviare più voci di menu insieme, e implementiamone i principali metodi (Add, Remove, Insert, IndexOf). Poi creiamo la classe MenuItemSettings, che rappresenta l'elemento XML della nostra custom section, contenente un'unica proprietà, di tipo MenuItemCollection, utile a rappresentare l'elemento MenuItems (che appunto contiente una collezione di oggetti di tipo MenuItem). Il codice di queste classi è davvero semplice e presente nel file .zip da scaricare.
Infine dobbiamo creare il nostro custom section handler, scrivendo una classe che implementi l'interfaccia IConfigurationSectionHandler.
Ecco il metodo Create di questa classe (che ho desciso di chiamare MenuConfigurator):

public object Create(object parent, object configContext, XmlNode section)
{
  MenuItemSettings settings = null;

  if (section == null) { return settings; }

  settings = new MenuItemSettings();

  XmlNodeList items = section.SelectNodes(@"MenuItems/MenuItem");
      
  for (int i=0; i   {
    XmlNode node = items.Item(i);
    MenuItem item = new MenuItem();
    item.DisplayName = node.Attributes["DisplayName"].InnerText;
    item.Href = node.Attributes["Href"].InnerText;
    item.Target = node.Attributes["Target"].InnerText;
    settings.MenuItems.Add(item);
  }
  return settings;
}

Come vedete questa non fa altro che parsare il codice XML della nostra custom section ed assegnare i valori dei vari attributi ad un nuovo oggetto di tipo MenuItem; questo oggetto viene infine aggiunto alla collezione. Ci rimane facile quindi, recuperare tutti i valori della sezione...

MenuItemSettings settings =
    (MenuItemSettings)ConfigurationSettings.GetConfig("MenuItemSettings");
foreach(MenuItem item in settings.MenuItems)
{
  Console.WriteLine(item.DisplayName+" ("+item.Href+")");
}

Conclusioni
Con questa serie di esempi abbiamo cercato di vedere tutti i possibili modi che ci vengono offerti dal .NET Framework, per pesonalizzare le sezioni dei file di configurazione delle nostre applicazioni e leggerne i valori a run-time. Queste tecniche risultano essere molto utili in applicazioni di grandi dimensioni che necessitano di variabili base che possono comunque essere modificate con facilità (perché ricordiamo che una modifica ai file .config non necessita di ricomplilazione).
Nel seguente file da scaricare troverete il codice sorgente utile per vedere l'applicazione in funzione.


Link utili:
Namespace System.Configuration
Interfaccia IConfigurationSectionHandler
Classe DictionarySectionHandler
Classe IgnoreSectionHandler
Classe NameValueSectionHandler
Classe SingleTagSectionHandler

Si ringrazia PeppeDotNet.it per la gentile concessione dell'articolo.




Utenti connessi: 5921