Seit dem .NET Framework 2.0 gibt es neue Möglichkeiten, eigene ConfigurationSection für eine App.config zu implementieren. Früher musste dazu das System.Configuration.IConfigurationSectionHandler Interface abgeleitet werden, welches aber nun deprecated ist. Nun bot sich für meine kleine StartUp-Applikation an, die ConfigurationSection zu benutzen.
Mich hat schon länger das Bootverhalten meines Rechners genervt. Alle Programme starten gleichzeitig, das kann man doch tunen! Aus diesem Grunde habe ich mir eine kleine StartUp-Applikation erstellt, welche Programme nach einer bestimmen Zeit nacheinander startet. Dazu habe ich mir meine eigene App.config Section überlegt. Der schnellste Weg ohne eine eigene ConfigurationSection wäre mit NameValueCollection gewesen. NameValueCollection verwaltet aber nur einen Key und ein Attribut und gerade wenn man mit mehr als Attributen arbeiten will, bietet sich eine eigene ConfigurationSection an. Auf geht es!
Folgende XML Struktur soll die ConfigurationSection einlesen:
App.config -
Copy Code1<programSettings>
2 <programToStart delayBeforeStartSeconds="0">
3 <programToStartList >
4 <add programName="test.exe" startNextDelaySeconds="0"/>
5 <add programName="test1.exe" startNextDelaySeconds="0"
6 startOption="/startup" />
7 </programToStartList>
8 </programToStart>
9</programSettings>
Es gibt folgende Attribute:
| delayBeforeStartSeconds |
Gibt an, wie lange die Applikation warten soll, bis das erste Programm gestartet wird |
| programName |
Programmname des zu startenden Programms |
| startNextDelaySeconds |
Gibt die Wartezeit an, bis das nächste Programm gestartet werden soll |
| startOption |
Falls das Programm Startoptionen hat, können die hier hinterlegt werden. |
Was benötigen wir noch? Wir brauchen eine ConfigurationSection-Klasse, eine ConfigurationElement-Klasse, welche die Attribute ausliest und eine ConfigurationElementCollection-Klasse, die die Iteration über die einzelnen ConfigurationElemente übernimmt.
Als erstes müssen wir eine Klasse (ProgramToStartConfiguration) erstellen, dazu müssen wir von der
ConfigurationSection-Klasse ableiten:
ConfigurationSection - Klasse -
Copy Code 1 public class ProgramToStartConfiguration : ConfigurationSection
2 {
3 private ConfigurationPropertyCollection _properties;
4
5 private ConfigurationProperty _programToStartList;
6 private readonly ConfigurationProperty _delayBeforeStartSeconds;
7
8 public ProgramToStartConfiguration()
9 {
10 _programToStartList = new
ConfigurationProperty("programToStartList",
typeof(ProgramToStartList));
11 _delayBeforeStartSeconds =
12 new ConfigurationProperty("delayBeforeStartSeconds",
13 typeof(int), (int)1000,
14 ConfigurationPropertyOptions.None);
15 _properties =
16 new ConfigurationPropertyCollection();
17
18 _properties.Add(_programToStartList);
19 _properties.Add(_delayBeforeStartSeconds);
20
21 }
22
23 [IntegerValidator(MinValue = 1, MaxValue = 10000,
24 ExcludeRange = false)]
25 public int TimeBeforeStart
26 {
27 get { return (int)this["delayBeforeStartSeconds"]; }
28 set { this["delayBeforeStartSeconds"] = value; }
29 }
30 [ConfigurationProperty("programToStartList")]
31 public ProgramToStartList ProgramToStartList
32 {
33 get { return base[_programToStartList] as ProgramToStartList; }
34 }
35
36 protected override ConfigurationPropertyCollection Properties
37 {
38 get { return _properties; }
39 }
40 }
Wie man in der XML Darstellung (s. Zeile 2) sehen kann, ist die ConfigurationSection als "programToStart" bezeichnet
und enthält das Attribut "delayBeforeStartSeconds". Damit wir das Attribut auslesen können, müssen wir ein passendes
ConfigurationProperty (s. Zeile 12-15) erstellen. Damit wir das Property ansprechen können, müssen wir es noch nach außen hin sichtbar machen (s. Zeile 24-30). Passend dazu habe ich einen
IntegerValidator erstellt, da der Wert der benötigten Zahl zwischen 1 und 10000 liegen soll. Was jetzt noch fehlt, ist die
ConfigurationPropertyCollection zur Verwaltung der Properties.
In Zeile 3-6 der XML Section ist eine Auflistung von mehreren Elementen zu sehen. Damit wir so eine Auflistung als Collection erstellen können, muss die ConfigurationElementCollection-Klasse (ProgramToStartList) erstellt werden:
ConfigurationElementCollection - Klasse -
Copy Code 1 public class ProgramToStartList : ConfigurationElementCollection
2 {
3 protected override ConfigurationElement CreateNewElement()
4 {
5 return new ProgramToStart();
6 }
7
8 protected override object GetElementKey(ConfigurationElement element)
9 {
10 if (element is ProgramToStart)
11 return ((ProgramToStart) element).ProgramName;
12 else
13 throw new ArgumentException("The specified element is
14 not of the correct type.");
15 }
16 }
Die Klasse erfordert die beiden Methoden CreateNewElement() und GetElementKey(). Damit die Attribute von einem Element ausgelesen werden können, benötigen wir noch eine ConfigurationElement-Klasse:
ConfigurationElement - Klasse -
Copy Code 1 public class ProgramToStart : ConfigurationElement
2 {
3 private ConfigurationPropertyCollection _properties;
4 private readonly ConfigurationProperty _programName;
5 private readonly ConfigurationProperty _startNextDelaySeconds;
6 private readonly ConfigurationProperty _startOption;
7
8 protected override ConfigurationPropertyCollection Properties
9 {
10 get { return this._properties; }
11 }
12
13 public ProgramToStart()
14 {
15 _programName = new ConfigurationProperty("programName",
16 typeof (string),"",
17 ConfigurationPropertyOptions.IsRequired);
18 _startNextDelaySeconds =
19 new ConfigurationProperty("startNextDelaySeconds",
20 typeof (int), (int) 1000,
21 ConfigurationPropertyOptions.None);
22 _startOption = new ConfigurationProperty("startOption",
23 typeof(string), "");
24 _properties =
25 new ConfigurationPropertyCollection();
26
27 _properties.Add(_programName);
28 _properties.Add(_startNextDelaySeconds);
29 _properties.Add(_startOption);
30 }
31
32 [IntegerValidator(MinValue = 1, MaxValue = 10000,
33 ExcludeRange = false)]
34 public int StartNextDelaySeconds
35 {
36 get { return (int) this["startNextDelaySeconds"]; }
37 set { this["startNextDelaySeconds"