Login
Konfigurace v .NET

Nevyhovuje vám obyčejná kolekce klíčů a hodnot v sekci appSettings ? Chcete mít vlastní sekci s komplexní datovou strukturou ? Preferujete silně typový objektový přístup ? Pak by se vám mohl hodit následující konfigurační handler založený na XML serializaci.

public class SerializationSectionHandler:IConfigurationSectionHandler
{
	public object Create(object parent,object configContext,XmlNode section)
	{
		object result;
		
		const string attributeTypeName = "type";
		XmlAttribute attributeType = section.Attributes[attributeTypeName,"http://schemas.viga.cz/Samples/SerializationSectionHandler"];
		if (attributeType == null) throw new ConfigurationErrorsException(string.Format("Attribute \"{0}\" not found.",attributeTypeName),section);
		Type type = Type.GetType(attributeType.Value);
		if (type == null)
		{
			int index = attributeType.Value.IndexOf(',');
			if (index >= 0)
			{
				Assembly.Load(attributeType.Value.Substring(index + 1).Trim());
				type = Type.GetType(attributeType.Value);
			}
		}
		if (type == null) throw new ConfigurationErrorsException(string.Format("Type \"{0}\" not found.",attributeType.Value),section);
		
		XmlRootAttribute root = new XmlRootAttribute(section.Name);
		root.Namespace = section.NamespaceURI;
		using (XmlReader reader = new XmlNodeReader(section))
		{
			try
			{
				result = new XmlSerializer(type,root).Deserialize(reader);
			}
			finally
			{
				reader.Close();
			}
		}
		
		return result;
	}
}
		

Napíšete si třídu, která bude popisovat strukturu vaší konfigurační sekce. Tato třída musí být serializovatelná do XML. Nejjednodušeji toho dosáhnete tak, že u požadovaných veřejných vlastností implementujete get i set metody. Nemusíte se omezovat pouze na jednoduché textové vlastnosti, ale můžete tvořit daleko složitější datové struktury s různými datovými typy, enumerátory, kolekcemi, atd. Pomocí různých atributů v namespace System.Xml.Serialization můžete ovlinit i XML strukturu vaší sekce v config souboru.

Abych ukázal co nejširší možnosti tohoto handleru, zvolil jsem pro následující příklad fiktivní datovou strukturu popisující hudební album. Tato sekce obsahuje různé vlastnosti typu string, jednu vlasnost typu DateTime, enumerátor je použit pro kategorizaci alba podle žánru a je tam také kolekce skladeb. Abych to zase príliš nekomplikoval, neaplikoval jsem žádné xml serilizační atributy, takže všechny vlastnosti jsou serializovány jako elementy pod stejným názvem.

public enum Genre
{
	None,
	Pop,
	Rock,
	Classic
}

public class Album
{
	private string title = null;
	private string artist = null;
	private Genre genre = Genre.None;
	private string publisher = null;
	private DateTime released = DateTime.MinValue;
	private Collection<Song> songs = null;
	
	public string Title
	{
		get {return title;}
		set {title = value;}
	}
	
	public string Artist
	{
		get {return artist;}
		set {artist = value;}
	}
	
	public Genre Genre
	{
		get {return genre;}
		set {genre = value;}
	}
	
	public string Publisher
	{
		get {return publisher;}
		set {publisher = value;}
	}
	
	public DateTime Released
	{
		get {return released;}
		set {released = value;}
	}
	
	public Collection<Song> Songs
	{
		get {return songs;}
		set {songs = value;}
	}
}

public class Song
{
	private string title = null;
	private string composer = null;
	private TimeSpan length = TimeSpan.Zero;
	
	public string Title
	{
		get {return title;}
		set {title = value;}
	}
	
	public string Composer
	{
		get {return composer;}
		set {composer = value;}
	}
}
		

Vlastní sekci si zaregistrujete běžným postupem. Jako typ handleru použijete výše uvedenou třídu SerializationSectionHandler. První element vaší sekce musí obsahovat atribut type, kde nastavíte typ vaší třídy do které bude tato sekce serializována. Atribut musí být plně kvalifikovaný včetně namespace, který používá handler k nalezení tohoto atributu, aby se zamezilo konfliktu se stejným atributem, který by mohla používat vaše třída. Pro náš fiktivní příklad by tedy konfigurační soubor mohl vypadat takto.

<configuration>
	<configSections>
		<section name="Album" type="Sample.SerializationSectionHandler,Sample"/>
	</configSections>
	
	<Album xmlns:ssh="http://schemas.viga.cz/Samples/SerializationSectionHandler" ssh:type="Sample.Album,Sample">
		<Title>Baptism</Title>
		<Artist>Lenny Kravitz</Artist>
		<Genre>Rock</Genre>
		<Publisher>EMI</Publisher>
		<Released>2004-05-18</Released>
		<Songs>
			<Song>
				<Title>Minister of Rock 'N Roll</Title>
				<Composer>C. Ross; Lenny Kravitz</Composer>
			</Song>
			<Song>
				<Title>I Don't Want to Be a Star</Title>
				<Composer>Lenny Kravitz</Composer>
			</Song>
			<Song>
				<Title>Lady</Title>
				<Composer>C. Ross; Lenny Kravitz</Composer>
			</Song>
			<Song>
				<Title>Calling All Angels</Title>
				<Composer>Lenny Kravitz</Composer>
			</Song>
			<Song>
				<Title>California</Title>
				<Composer>Lenny Kravitz</Composer>
			</Song>
			<Song>
				<Title>Sistamamalover</Title>
				<Composer>Lenny Kravitz</Composer>
			</Song>
			<Song>
				<Title>Where Are We Runnin'?</Title>
				<Composer>C. Ross; Lenny Kravitz</Composer>
			</Song>
			<Song>
				<Title>Baptized</Title>
				<Composer>Britten; Deveaux; Lenny Kravitz</Composer>
			</Song>
			<Song>
				<Title>Flash</Title>
				<Composer>Lenny Kravitz</Composer>
			</Song>
			<Song>
				<Title>What Did I Do With My Life?</Title>
				<Composer>Lenny Kravitz</Composer>
			</Song>
			<Song>
				<Title>Storm</Title>
				<Composer>Carter; Lenny Kravitz</Composer>
			</Song>
			<Song>
				<Title>The Other Side</Title>
				<Composer>Lenny Kravitz</Composer>
			</Song>
			<Song>
				<Title>Destiny</Title>
				<Composer>Lenny Kravitz; Richie</Composer>
			</Song>
		</Songs>
	</Album>
</configuration>
		

A takto může vypadat kód v aplikaci, který použivá vaší vlastní konfigurační sekci.

public static void Main()
{
	Album album = (Album) ConfigurationManager.GetSection("Album");
	Console.WriteLine("Title:     {0}",album.Title);
	Console.WriteLine("Artist:    {0}",album.Artist);
	Console.WriteLine("Genre:     {0}",album.Genre);
	Console.WriteLine("Publisher: {0}",album.Publisher);
	Console.WriteLine("Released:  {0}",album.Released);
	Console.WriteLine();
	Console.WriteLine("Title".PadRight(30) + "Composer".PadRight(30));
	foreach (Song song in album.Songs) Console.WriteLine(song.Title.PadRight(30) + song.Composer.PadRight(30));
}
		

V .NET 2.0 už je sice větší podpora komplexnějších datových struktur v konfiguračních souborech, ale přidala se k tomu i podpora pro ukládání, takže v mnoha případech může jít o zbytečně složité rešení. Pro read-only konfigurační sekce může být tento handler jednodušší cestou.

Number of comments: 0