In dem HowTo geht es darum wie man die Web.config zur Laufzeit ändert und was es dabei zu beachten gilt. Das ganze klappt auch mit komplexeren ConfigSections.
Eigene ConfigSection?
Vor einer ganzen Weile habe ich mal über das Erstellen einer eigenen ConfigSection geschrieben – im Grunde nutzen wir jetzt fast dieselbe Config.
Zur Laufzeit? Startet da die Webapplikation nicht neu?
Im Grunde ist das auch richtig. Ändert man die web.config wird die Applikation neugestartet. Allerdings läuft der Request der zur Änderung geführt hat noch durch. Ich würde aber nicht empfehlen solch eine Änderung häufiger zu machen, sondern beim Aufsetzen der Webanwendung etc. Aber im Grunde funktioniert es auch ziemlich gut ;)
Zum Code
Die Definition der ConfigSection:
public class CodeInsideConfig : ConfigurationSection { [ConfigurationProperty("webUrl", DefaultValue = "http://DEFAULT.de", IsRequired = true)] public string WebUrl { get { return this["webUrl"] as string; } } [ConfigurationProperty("id", IsRequired = false)] public Guid Id { get { return (Guid)this["id"]; } set { this["id"] = value; } } [ConfigurationProperty("authors")] public CodeInsideConfigAuthorCollection Authors { get { return this["authors"] as CodeInsideConfigAuthorCollection; } } public static CodeInsideConfig GetConfig() { return ConfigurationSettings.GetConfig("codeInsideConfig") as CodeInsideConfig; } public static Configuration GetWritableBaseConfig() { return WebConfigurationManager.OpenWebConfiguration("~"); } } public class CodeInsideConfigAuthorCollection : ConfigurationElementCollection { public CodeInsideConfigAuthor this[int index] { get { return base.BaseGet(index) as CodeInsideConfigAuthor; } set { if (base.BaseGet(index) != null) { base.BaseRemoveAt(index); } this.BaseAdd(index, value); } } public void Add(CodeInsideConfigAuthor appElement) { BaseAdd(appElement); } protected override ConfigurationElement CreateNewElement() { return new CodeInsideConfigAuthor(); } protected override object GetElementKey(ConfigurationElement element) { return ((CodeInsideConfigAuthor)element).Name; } } public class CodeInsideConfigAuthor : ConfigurationElement { [ConfigurationProperty("name", IsRequired = true)] public string Name { get { return this["name"] as string; } set { this["name"] = value; } } }
Anders als im ursprünglichem Blogpost haben die einzelnen ConfigurationElements auch not Setter und die Collection hat noch eine BaseAdd Methode (welche als Protected Method in der Basisklasse vorhanden ist). Die ConfigSection muss natürlich auch in der Web.config bekannt sein:
<configSections> <section name="codeInsideConfig" type="UpdatableWebConfig.CodeInsideConfig"/> </configSections>
Zur Anwendung des Codes…
Das Ganze ist jetzt in einer Standard MVC Applikation im HomeController eingebunden:
public ActionResult Index() { var config = CodeInsideConfig.GetConfig(); ViewBag.Url = config.WebUrl; ViewBag.Id = config.Id; ViewBag.NumberOfAuthors = config.Authors.Count; return View(); } public ActionResult About() { var config = CodeInsideConfig.GetWritableBaseConfig(); var writableConfigSection = config.GetSection("codeInsideConfig") as CodeInsideConfig; writableConfigSection.Id = Guid.NewGuid(); writableConfigSection.Authors.Add(new CodeInsideConfigAuthor() { Name = "Hello World!" + Guid.NewGuid() }); try { config.Save(); return RedirectToAction("Index", "Home"); } catch (ConfigurationErrorsException exc) { throw; } }
Im Index() wird nur gelesen und im About() werden neue Werte eingetragen.
Erklärung:
ConfigurationSettings.GetConfig(…) gibt immer nur lesenden Zugriff auf die Web.config Einträge.
Zum Schreiben benötigt man den Zugriff über den WebConfigurationManager. Danach kann man auch Save aufrufen. Danach wird auch direkt die Config aktualisiert und nachdem der Request durch ist wird auch die Webapplikation neugestartet.
Bei Fehlern kann evtl. eine ConfigurationErrorsException auftreten, daher der “tote” Code im Beispiel.
Den gesamten Code gibts auch auf GitHub.