-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathEnvironmentConfigurationBuilder.cs
155 lines (133 loc) · 4.93 KB
/
EnvironmentConfigurationBuilder.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
using System;
using System.Collections;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Xml;
namespace Solid.Containers.Configuration
{
public class EnvironmentConfigurationBuilder : ConfigurationBuilder
{
private const string KeyPrefix = "ASPNET";
public override XmlNode ProcessRawXml(XmlNode rawXml)
{
if (rawXml.LocalName == "appSettings") return ProcessAppSettingsXml(rawXml);
if (rawXml.LocalName == "connectionStrings") return ProcessConnectionStringsXml(rawXml);
return ProcessCustomConfigurationSection(rawXml);
}
private XmlNode ProcessCustomConfigurationSection(XmlNode section)
{
var prefix = $"{KeyPrefix}__{section.LocalName}__";
var environment = GetEnvironmentVariables();
var keys = environment.Keys.Where(key => key.StartsWith(prefix));
foreach (var key in keys)
{
var path = ParsePath(key);
var xml = section;
foreach (var part in path.Item1)
{
var element = null as XmlElement;
if (part.Index == null)
element = xml[part.Name];
else
element = xml.ChildNodes.OfType<XmlElement>().ElementAtOrDefault(part.Index.Value);
if (element == null)
{
element = xml.OwnerDocument.CreateElement(part.Name, section.NamespaceURI);
xml.AppendChild(element);
}
xml = element;
}
var attribute = xml.Attributes[path.Item2];
if (attribute == null)
{
attribute = xml.OwnerDocument.CreateAttribute(path.Item2);
xml.Attributes.Append(attribute);
}
attribute.Value = environment[key];
}
return section;
}
private XmlNode ProcessAppSettingsXml(XmlNode appSettings)
{
var environment = GetEnvironmentVariables();
var settings = appSettings.ChildNodes.OfType<XmlElement>().ToDictionary(n => n.Attributes["key"].Value, n => n.Attributes["value"]);
foreach (var variable in environment)
{
var prefix = $"{KeyPrefix}__appSettings__";
if (!variable.Key.StartsWith(prefix)) continue;
var key = variable.Key.Substring(prefix.Length);
if (settings.ContainsKey(key))
{
settings[key].Value = variable.Value;
continue;
}
// Add the app setting if missing from original configuration
var element = appSettings.OwnerDocument.CreateElement("add");
var elementKey = appSettings.OwnerDocument.CreateAttribute("key");
elementKey.Value = key;
element.Attributes.Append(elementKey);
var elementValue = appSettings.OwnerDocument.CreateAttribute("value");
elementValue.Value = variable.Value;
element.Attributes.Append(elementValue);
appSettings.AppendChild(element);
}
return appSettings;
}
private XmlNode ProcessConnectionStringsXml(XmlNode connectionStrings)
{
var environment = GetEnvironmentVariables();
var connections = connectionStrings.ChildNodes.OfType<XmlElement>().ToDictionary(n => n.Attributes["name"].Value, n => n.Attributes["connectionString"]);
foreach (var variable in environment)
{
var prefix = $"{KeyPrefix}__connectionStrings__";
if (!variable.Key.StartsWith(prefix)) continue;
var name = variable.Key.Substring(prefix.Length);
if (connections.ContainsKey(name))
connections[name].Value = variable.Value;
// Skip the connection if missing from original configuration
}
return connectionStrings;
}
private Dictionary<string, string> GetEnvironmentVariables()
{
var environment = Environment
.GetEnvironmentVariables();
var variables = environment
.Keys
.OfType<string>()
.ToDictionary(k => k, k => environment[k].ToString(), StringComparer.OrdinalIgnoreCase)
;
return variables;
}
private (ElementDescription[], string) ParsePath(string key)
{
var split = key.Split(new[] { "__" }, StringSplitOptions.RemoveEmptyEntries).Skip(2); // skip prefix and section element name
if (split.Count() == 0) return (new ElementDescription[0], null);
var attribute = split.LastOrDefault();
var path = split.Take(split.Count() - 1);
return (path.Select(Convert).ToArray(), attribute);
}
private ElementDescription Convert(string part)
{
var regex = new Regex(@"^(.*?)\[(\d+)\]$");
var match = regex.Match(part);
if (!match.Success) return new ElementDescription { Name = part };
return new ElementDescription
{
Index = int.Parse(match.Groups[2].Value),
Name = match.Groups[1].Value
};
}
class ElementDescription
{
public int? Index { get; set; }
public string Name { get; set; }
}
}
}