{"id":3484,"date":"2016-04-13T16:02:01","date_gmt":"2016-04-13T15:02:01","guid":{"rendered":"https:\/\/u-labs.de\/portal\/?p=3484"},"modified":"2016-04-13T16:02:22","modified_gmt":"2016-04-13T15:02:22","slug":"asp-net-mvc5-eigenen-benutzerdefinierten-bereich-in-der-web-config-datei-erstellen","status":"publish","type":"post","link":"https:\/\/u-labs.de\/portal\/asp-net-mvc5-eigenen-benutzerdefinierten-bereich-in-der-web-config-datei-erstellen\/","title":{"rendered":"ASP.NET MVC: Eigenen benutzerdefinierten Bereich in der Web.config Datei erstellen"},"content":{"rendered":"<p>Mit der Web.config bietet .NET eine zentrale Konfigurationsdatei f\u00fcr verschiedene Optionen der jeweiligen Anwendung. So kann beispielsweise die Ziel-Version des .NET Frameworks festgelegt werden. Sp\u00e4testens bei etwas komplexeren Anwendungen wird man den Bedarf feststellen, gewisse Parameter zur Laufzeit ver\u00e4ndern zu wollen. Dies erh\u00f6ht die Flexibilit\u00e4t und Wartbarkeit gegen\u00fcber hart kodierten Werten. Warum die eigenen Konfigurationsparameter nicht gleich in die bereits existierende Web.config einbinden? Damit f\u00e4llt das suchen in verschiedenen Dateien weg, da alles zentral in einer Konfigurationsdatei definiert ist. Dieser Artikel zeigt, wie man eigene Parameter in der Datei unterbringt und auf sie zugreift.<\/p>\n<h3><strong>Simple Schl\u00fcssel-Wert Paare speichern und auslesen<\/strong><\/h3>\n<p>Am einfachsten funktioniert dies mit Schl\u00fcssel-Wert Paaren oder auch <strong>KeyValue-Pair<\/strong> genannt. Man hat in diesem Fall also nur einen einzigen benannten Schl\u00fcssel, dem ein bestimmter Wert zugewiesen wird. Beispielsweise k\u00f6nnte man so einen Debug-Modus aktivieren oder einen Basis-Host definieren, der f\u00fcr bestimmte Abfragen (etwa an eine API) verwendet wird.\u00a0Im <strong>&lt;config&gt;<\/strong> Knoten suchen wir daf\u00fcr nach <strong>&lt;appSettings&gt;<\/strong>. Je nach Anwendungstyp ist dieser bereits vorhanden und mit einigen Schl\u00fcsselpaaren gef\u00fcllt, etwa in ASP.NET Webanwendungen. Falls nicht, kann dieser als leerer XML-Tag erstellt werden:<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;\r\n&lt;configuration&gt;\r\n  &lt;appSettings&gt;\r\n  &lt;\/appSettings&gt;\r\n&lt;\/configuration&gt;\r\n<\/pre>\n<p>In den\u00a0<strong>appSettings<\/strong> k\u00f6nnen wir nun\u00a0mit dem\u00a0<strong>add<\/strong> Element ein Schl\u00fcsselpaar hinzuf\u00fcgen:<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n&lt;appSettings&gt;\r\n  &lt;add key=&quot;enableDebugOutput&quot; value=&quot;true&quot; \/&gt;\r\n&lt;\/appSettings&gt;\r\n<\/pre>\n<p>Schl\u00fcssel (key) und Wert (value) k\u00f6nnen hierbei frei gew\u00e4hlt werden. Im Code der Anwendung lassen sich die Werte \u00fcber die ConfigurationManager-Klasse auslesen, wozu der Namensraum\u00a0<strong>System.Configuration<\/strong> importiert werden muss:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nbool debugModeEnabled = Convert.ToBoolean(ConfigurationManager.AppSettings&#x5B;&quot;enableDebugOutput&quot;]);\r\n<\/pre>\n<p>Das Umwandeln in den jeweiligen Zieltyp wird auf diese Art jedoch sp\u00e4testens dann l\u00e4stig, wenn man mehrere Integer- bzw. Boolean-Werte auslesen m\u00f6chte. Leider k\u00f6nnen wir die ConfigurationManager-Klasse nicht mit einer Erweiterungsmethode erg\u00e4nzen, da sie statisch ist. Daher ist eine kleine Hilfsklasse n\u00f6tig:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nusing System.ComponentModel;\r\nusing System.Configuration;\r\n\r\npublic static class AppSettings {\r\n    \/\/\/ &lt;summary&gt;\r\n    \/\/\/ Gibt den Wert eines Schl\u00fcssels im appSettings-Knoten der Web.config stark typisert zur\u00fcck oder wirft eine Exception, wenn der Wert nicht vorhanden bzw. leer ist. \r\n    \/\/\/ &lt;\/summary&gt;\r\n    \/\/\/ &lt;typeparam name=&quot;T&quot;&gt;Typ des R\u00fcckgabewertes&lt;\/typeparam&gt;\r\n    \/\/\/ &lt;param name=&quot;key&quot;&gt;Schl\u00fcssel des KeyValue-Pairs in der Konfigurationsdatei&lt;\/param&gt;\r\n    \/\/\/ &lt;returns&gt;&lt;\/returns&gt;\r\n    public static T Get&lt;T&gt;(string key) {\r\n        var appSetting = ConfigurationManager.AppSettings&#x5B;key];\r\n        if (string.IsNullOrWhiteSpace(appSetting)) {\r\n            var exceptionMessage = string.Format(&quot;Der Schl\u00fcssel '{0}' wurde im appSettings-Abschnitt nicht gefunden oder besitzt einen leeren Wert!&quot;, key);\r\n            throw new ConfigurationErrorsException(exceptionMessage);\r\n        }\r\n\r\n        var converter = TypeDescriptor.GetConverter(typeof(T));\r\n        return (T)(converter.ConvertFromInvariantString(appSetting));\r\n    }\r\n}\r\n<\/pre>\n<p>Damit wird der Aufruf schon deutlich \u00fcbersichtlicher:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nbool debugModeEnabled = AppSettings.Get&lt;bool&gt;(&quot;enableDebugOutput&quot;);\r\n<\/pre>\n<p>Um den Scope m\u00f6glichst gering zu halten und die Fehleranf\u00e4lligkeit zu verringern, empfiehlt sich zudem eine Wrapper-Klasse:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\npublic static class MySettings {\r\n    public static bool DebugModeEnabled {\r\n        get {\r\n            return AppSettings.Get&lt;bool&gt;(&quot;enableDebugOutput&quot;);\r\n        }\r\n    }\r\n}\r\n<\/pre>\n<h3><strong>Eigene Bereich\u00a0erstellen<\/strong><\/h3>\n<p>Sp\u00e4testens wenn man mehrere zusammengeh\u00f6rende Werte speichern m\u00f6chte, ist die L\u00f6sung \u00fcber Schl\u00fcssel-Wert Paare nicht optimal. Doch daran wurde in .NET ebenfalls gedacht: Man kann \u00e4hnlich einfach benutzerdefinierte Bereiche (sogenannte\u00a0<strong>Sections<\/strong>) erstellen, denen sich beliebige Eigenschaften zuweisen lassen. Dazu erstellen wir zun\u00e4chst eine Wrapper-Klasse, die von <strong>ConfigurationSection<\/strong> erbt:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nusing System.Configuration;\r\n\r\npublic class DebugOptionsSection : ConfigurationSection {\r\n\r\n    &#x5B;ConfigurationProperty(&quot;enableDebugOutput&quot;)]\r\n    public bool EnableDebugOutput {\r\n        get { return (bool)this&#x5B;&quot;enableDebugOutput&quot;]; }\r\n    }\r\n\r\n    &#x5B;ConfigurationProperty(&quot;debugLogFile&quot;)]\r\n    public string DebugLogFile {\r\n        get { return (string)this&#x5B;&quot;debugLogFile&quot;]; }\r\n    }\r\n}\r\n<\/pre>\n<p>In der Web.config muss dieser Wrapper nun in den <strong>configSections<\/strong> registriert werden: <\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n&#x5B;csharp]\r\nusing System.Configuration;\r\n\r\npublic class DebugOptionsSection : ConfigurationSection {\r\n\r\n    &#x5B;ConfigurationProperty(&quot;enableDebugOutput&quot;)]\r\n    public bool EnableDebugOutput {\r\n        get { return (bool)this&#x5B;&quot;enableDebugOutput&quot;]; }\r\n    }\r\n\r\n    &#x5B;ConfigurationProperty(&quot;debugLogFile&quot;)]\r\n    public string DebugLogFile {\r\n        get { return (string)this&#x5B;&quot;debugLogFile&quot;]; }\r\n    }\r\n}\r\n&#x5B;\/csharp]\r\n<\/pre>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n&lt;configuration&gt;\r\n  &lt;configSections&gt;\r\n    &lt;section name=&quot;debugOptionsSection&quot; type=&quot;ULabs.DebugOptionSection&quot; \/&gt;\r\n  &lt;\/configSections&gt;\r\n&lt;\/configuration&gt;\r\n<\/pre>\n<p>Zu beachten ist, dass in der <strong>type<\/strong> Eigenschaft der vollqualifizierte Name angegeben werden muss &#8211; Also im Format Namespace.Klasse! <\/p>\n<p>Anschlie\u00dfend k\u00f6nnen wir den Bereich selbst definieren und entsprechend unseres Wrappers mit den ben\u00f6tigten Eigenschaften ausstatten:<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n&lt;configuration&gt;\r\n  &lt;debugOptionsSection enableDebugOutput=&quot;true&quot; debugLogFile=&quot;debug.log&quot; \/&gt;\r\n&lt;\/configuration&gt;\r\n<\/pre>\n<p>Zu guter Letzt wollen wir die dort angegebenen Werte nat\u00fcrlich noch codeseitig auslesen. \u00dcber die <strong>GetSection<\/strong> Methode des Konfigurationsmanagers erhalten wir eine Instanz dieser Wrapper-Klasse und k\u00f6nnen auf die Attribute zugreifen: <\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nvar debugConfig = (DebugOptionsSection)ConfigurationManager.GetSection(&quot;debugOptionsSection&quot;);\r\nif(debugConfig.EnableDebugOutput) {\r\n    \/\/ Debug-Ausgabe aktiviert\r\n}\r\n<\/pre>\n<p>Der Vorteil besteht hierbei in der m\u00f6glichen Verfeinerung der Konfiguration \u00fcber DataAnnotiation-Attribute. Beispielsweise k\u00f6nnen wir im <strong>ConfigurationProperty<\/strong> mit der Eigenschaft <strong>DefaultValue<\/strong> einen Standardwert festlegen, wodurch wiederholende Pr\u00fcfungen und Zuweisungen vermieden werden:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\n    &#x5B;ConfigurationProperty(&quot;enableDebugOutput&quot;, DefaultValue = false)]\r\n    public bool EnableDebugOutput {\r\n        get { return (bool)this&#x5B;&quot;enableDebugOutput&quot;]; }\r\n    }\r\n<\/pre>\n<p>Auch umfangreichere Validierungen sind m\u00f6glich. So l\u00e4sst sich beispielsweise die L\u00e4nge von Strings begrenzen oder ihr Inhalt mit regul\u00e4ren Ausdr\u00fccken pr\u00fcfen. Dies weiter auszuf\u00fchren w\u00fcrde den Rahmen dieses Artikels jedoch etwas sprengen. Au\u00dferdem gibt es diesbez\u00fcglich bereits einen guten Artikel in der MSDN von Microsoft: <a href=\"https:\/\/msdn.microsoft.com\/de-de\/library\/2tw134k3(v=vs.100).aspx\" target=\"_blank\" rel=\"nofollow\">Erstellen von benutzerdefinierten Konfigurationsabschnitten mit ConfigurationSection<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Mit der Web.config bietet .NET eine zentrale Konfigurationsdatei f\u00fcr verschiedene Optionen der jeweiligen Anwendung. So kann beispielsweise die Ziel-Version des .NET Frameworks festgelegt werden. Sp\u00e4testens bei etwas komplexeren Anwendungen wird man den Bedarf feststellen, gewisse Parameter zur Laufzeit ver\u00e4ndern zu wollen. Dies erh\u00f6ht die Flexibilit\u00e4t und Wartbarkeit gegen\u00fcber hart kodierten Werten. Warum die eigenen Konfigurationsparameter &#8230;<\/p>\n","protected":false},"author":5,"featured_media":3496,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[61],"tags":[331,336,413,426,330,408],"class_list":["post-3484","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-softwareentwicklung","tag-net","tag-asp-net","tag-asp-net-mvc","tag-asp-net-mvc6","tag-c","tag-web-config"],"_links":{"self":[{"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/posts\/3484","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/comments?post=3484"}],"version-history":[{"count":14,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/posts\/3484\/revisions"}],"predecessor-version":[{"id":3930,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/posts\/3484\/revisions\/3930"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/media\/3496"}],"wp:attachment":[{"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/media?parent=3484"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/categories?post=3484"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/tags?post=3484"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}