Vytvorme si vlastnú sekciu v konfiguračnom súbore (I.) - Úvod

.NET priniesol príjemný spôsob, ako pracovať a uchovávať konfiguračné nastavenia aplikácie. Staré registry alebo rôzne ini súbory, cez ktoré nastavenia riešili aplikácie v minulosti, nahradil koncept založený na XML. S príchodom .NET 2.0 sa možnosti práce s configuračnými súbormi ešte rozšírili resp. zmenila sa celá infraštruktúra pracujúca s configuračnými súbormi. Aj keď si väčšina malých aplikácií vystačí s pár nastaveniami, kde sa možno uspokojíme len s pridaním kľúčov do známej AppSettings sekcie, pri serióznejšej aplikácii s väčším množstvom nastavení, s množstvo klúčov na jednej úrovni XML strácame prehladnosť a výhody, ktoré prináša XML, nevieme ich striktne validovať, nevieme s nimi pracovať inak ako s reťazcami, teda máme prácu s parsovaním iných typov ako reťazec. Ukážeme si postup, ako si vytvoriť vlastnú konfiguračnú sekciu, ako s ňou pracovať, úkažme si možnosti, ktoré priniesol .NET Framework 2.0.

Ano, aj AppConfig je jedna z mnohých konfiguračných sekcií, ktoré je možné vytvoriť v configuračnom súbore a ktoré vie "oparsovať" konfiguračná infraštruktúra.

Qvízová otázka. Ako zistím, keď mi zoberú MSDN :-), aké sekcie sú povolené v konfiguračných súboroch v mojich aplikáciach?

Správna odpoveď je, ako inak, pohľadom do machine.config (C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\CONFIG). Hneď na začiatku vidíme zaregistrovanú nám už známu AppSetting sekciu, ktorej zodpovedá wrapper trieda System.Configuration.AppSettingsSection.

<configuration>
    <configSections>
        <section name="appSettings" type="System.Configuration.AppSettingsSection,
System.Configuration, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a"
restartOnExternalChanges="false"
requirePermission="false" /> ... </configuration>

Čo bude teda našim cieľom?

  1. Chceme vytvoriť vlastný konfiguračnú sekciu :-)
  2. Sekciu chceme zaregistrovať a oznámiť konfiguračnej infraštruktúre, aby s ňou počítala
  3. Chceme vytvárať hierarchické štruktúry. S jednou úrovňou vlastnej konfigurácie si nevystačíme
  4. Chceme pracovať s kolekciou hodnôt v konfiguračnom súbore
  5. Chceme jednoducho deklaratívne výnutiť validovanie obsahu toho, čo je hodnotou daného nastavenia v rámci sekcie
  6. Chceme programovo modifikovať nastavenia
  7. Chceme zakryptovať sekciu
  8. Chýba Vám tu niečo? Dajte prosím vedieť...

1. Vlastná konfiguračná sekcia

Postup je veľmi jednoduchý. Stáčí, ak zdedíme z triedy System.Configuration.ConfigurationSection a každú public property zodpovedajúcu zamýšľanému atribútu v konfiguračnom súbore ozdobíme atribútom ConfigurationProperty. .NET Framework prostredníctvom refletion prečíta tieto atribúty a vytvorí zodpovedajúcu inštanciu ConfigurationProperty triedy. Prvou property atribútu ConfigurationProperty je názov konfiguračného elementu, na ktorú je daná dekorovaná property mapovaná. Pozor, názov je case senzitívny. Ďalej máme možnosť určiť, či je daná property v rámci konfigurácie povinná a prednastaviť jej hodnotu.

using System;
using System.Configuration;

namespace ASPNET.Config
{
    public class TestConfigurationSection : ConfigurationSection
    {
        [ConfigurationProperty("pageSize", DefaultValue=10)]
        public int PageSize
        {
            get { return (int)this["pageSize"]; }
            set { this["pageSize"] = value; }
        }

        [ConfigurationProperty("contactEmail", IsRequired = true)]
        public string ContactEmail
        {
            get { return (string)this["contactEmail"]; }
            set { this["contactEmail"]= value; }
        }
    }
}

2. Zaregistrovanie sekcie

Opať veľmi jednoduchý krok, stačí v našom web.configu pridať do configSection elementu section element, vymyslieť názov pre našu sekciu a zadeklarovať, ktorá trieda ju bude wrappovať, v tomto prípade nami vytvorená TestConfigurationSection. Následne si možeme pridať rošíriť web.config o našu konfiguráciu pre test.

<configuration>
    <configSections>
        <section name="TestConfig" type="ASPNET.Config.TestConfigurationSection"/>
    </configSections>
    <TestConfig pageSize="20" contactEmail="tomas@aspnet.sk"/>
</configuration>

Ako prečítať nastavenia z aplikácie? Urobíme si testovaciu stránku, na ktorú umiestnime Literal control.

<asp:Literal ID="LtrTest" runat="server" Mode="PassThrough"/> 

V code behind súbore prostredníctvom ConfigurationManagera vyhľadáme danú konfiguračnú sekciu a zobrazíme jej atribúty.

using System;
using System.Configuration;

using ASPNET.Config;

public partial class _Default : System.Web.UI.Page 
{
    protected override void OnLoad(EventArgs e)
    {
        TestConfigurationSection testConfig= 
(TestConfigurationSection) ConfigurationManager.GetSection("TestConfig"); LtrTest.Text = String.Format("<strong>Contact email:</strong> {0}
<br><strong>Page Size:</strong> {1}<br>"
, testConfig.ContactEmail, testConfig.PageSize); base.OnLoad(e); } }

Aletrnatívnym nedeklaratívnym spôsobom by sme mohli vytvoriť sekciu takto:

public class TestConfigurationSection : ConfigurationSection
{        
    private static ConfigurationPropertyCollection _properties = new 

ConfigurationPropertyCollection();
    private static ConfigurationProperty _pageSize, _contactEmail;

    static TestConfigurationSection()
    {
        _pageSize = new ConfigurationProperty("pageSize", typeof(int));
        _contactEmail = new ConfigurationProperty("contactEmail", typeof(string));

        _properties.Add(_pageSize);
        _properties.Add(_contactEmail);
    }

    protected override ConfigurationPropertyCollection Properties
    {
        get { return _properties; }
    }
    
    public int PageSize
    {
        get { return (int)this[_pageSize]; }
        set { this[_pageSize] = value; }
    }
    
    public string ContactEmail
    {
        get { return (string)this[_contactEmail]; }
        set { this[_contactEmail] = value; }
    }
}

Takže máme vlastný konfiguračný element, ktorý môžeme znovapoužívať v rôznych projektoch, stačí, ak sa stane súčasťou samostatnej knižnice a zaregistrujeme ju v projektu zodpovedajúcom konfiguračnom súbore. Alternatívne aj keď z hľadiska praxe asi ťažko zmysluplne, by sme ho mohli pridať napr. do machine.config.

Ako zapuzdriť príbuzné konfiguračné sekcie do spoločného elementu? Naše registrované sekcie vnoríme v našom konfiguračnom súbore do sectionGroup elementu.

<configuration>
    <configSections>
            <sectionGroup name="ASPNET.Web">
            <section name="TestConfig" type="ASPNET.Config.TestConfigurationSection"/>
            </sectionGroup>  
    </configSections>

    <ASPNET.Web>
        <TestConfig pageSize="20" contactEmail="tomas@aspnet.sk"/>
    </ASPNET.Web>
</configuration>

Musíme potom ešte upraviť cestu konfiguračnej sekcie, keď ku nej pristupujeme programovo cez ConfigurationManagera.

TestConfigurationSection testConfig= (TestConfigurationSection) ConfigurationManager.GetSection("ASPNET.Web/TestConfig");

Vytvorenie hierarchickej štruktúry v konfiguračnej sekcii

Skúsme teraz vnoriť další element do našej konfiguračnej sekcie. Ten bude obsahovať vlastné atribúty. Ako základ použijeme triedu ConfigurationElement, z ktorej zdedíme a properties pridáme a ozdobíme atribútmi podobne, ako predtým keď sme vytvárali našu ConfigurationSection.

using System;
using System.Configuration;

namespace ASPNET.Config
{    
    public class PagerConfigurationElement : ConfigurationElement
    {
        [ConfigurationProperty("pageSize", DefaultValue = 10)]
        public int PageSize
        {
            get { return (int)this["pageSize"]; }
            set { this["pageSize"] = value; }
        }

        [ConfigurationProperty("maxVisiblePages", DefaultValue = 5)]
        public int MaxVisiblePages
        {
            get { return (int)this["maxVisiblePages"]; }
            set { this["maxVisiblePages"] = value; }
        }
    }
}

Element zapracujeme do pôvodnej konfiguračnej sekcie tak, že vytvoríme property totožnú s názvom elementu v kofiguračnom súbore typu PagerConfigurationElement.

public class TestConfigurationSection : ConfigurationSection
{
    [ConfigurationProperty("Pager",IsRequired=true)]
    public PagerConfigurationElement Pager
    {
        get { return (PagerConfigurationElement)this["Pager"]; }
        set { this["Pager"] = value; }
    }

    [ConfigurationProperty("contactEmail", IsRequired = true)]
    public string ContactEmail
    {
        get { return (string)this["contactEmail"]; }
        set { this["contactEmail"] = value; }
    }
}

Prispôsobíme configuračný súbor:

LtrTest.Text = String.Format("<strong>Contact email:</strong> {0}<br>
<
strong>Page Size:</strong> {1}<br><strong>Max. visible pages:</strong> {2}<br>", testConfig.ContactEmail, testConfig.Pager.PageSize, testConfig.Pager.MaxVisiblePages);

Náš testovací kód v OnLoad Handlery upravíme nasledovne:

LtrTest.Text = String.Format("<strong>Contact email:</strong> {0}<br>
<strong>Page Size:</strong> {1}<br><strong>Max. visible pages:</strong> {2}<br>"
, testConfig.ContactEmail, testConfig.Pager.PageSize, testConfig.Pager.MaxVisiblePages);

Príslušná modifikácia konfiguračného súboru:

<ASPNET.Web>
    <TestConfig contactEmail="tomas@aspnet.sk">
        <Pager pageSize="10" maxVisiblePages="20"/>
    </TestConfig>
</ASPNET.Web>

Web project s príkladmi ku článku

Pokračovanie nabudúce...

Komentáre

# skippo said:

Diky za clanok, je to naozaj elegantne a pritom jednoduche nez trapit sa s AppSettings pri vacsom pocte klucov.

Monday, July 02, 2007 4:32 PM
# T said:

To ja dakujem, ze viem, ze to aspon niekto cita a ze to ma zmysel...;-)

Monday, July 02, 2007 5:30 PM
# skippo said:

Cita neboj, len pri tvojej produktivite (dost sa divim ako to vsetko stihas) je to tazke precitat ihned, tak niekedy to trva aj nejaky ten den. Podakovanie je asi jedina podpora, ale asi najlepsia co ti mozem dat :-)

Tuesday, July 03, 2007 9:10 AM
# Tomáš - DevBlog said:

Doteraz bola práca s configuračnými sekciami a elementami veľmi jednoduchá. V prvom diely sme sa naučili vytvoriť handler pre konfiguračnú sekciu a zaregistrovať ho, vytvoriť konfiguračný element a zoskupovať jednotlivé sekcie.

Thursday, July 05, 2007 1:27 PM
Prihlásiť | Registrovať | Pomoc