Skip to content

Commit a490a34

Browse files
authored
Add ConfigurationManager(#55338)
* ConfigurationManager : IConfigurationRoot, IConfigurationBuilder
1 parent 9a9b105 commit a490a34

File tree

4 files changed

+1599
-26
lines changed

4 files changed

+1599
-26
lines changed

src/libraries/Microsoft.Extensions.Configuration/ref/Microsoft.Extensions.Configuration.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,21 @@ public ChainedConfigurationSource() { }
2828
public bool ShouldDisposeConfiguration { get { throw null; } set { } }
2929
public Microsoft.Extensions.Configuration.IConfigurationProvider Build(Microsoft.Extensions.Configuration.IConfigurationBuilder builder) { throw null; }
3030
}
31+
public sealed partial class ConfigurationManager : Microsoft.Extensions.Configuration.IConfigurationBuilder, Microsoft.Extensions.Configuration.IConfigurationRoot, System.IDisposable
32+
{
33+
public ConfigurationManager() { }
34+
public string this[string key] { get { throw null; } set { throw null; } }
35+
public IConfigurationSection GetSection(string key) { throw null; }
36+
public System.Collections.Generic.IEnumerable<IConfigurationSection> GetChildren() { throw null; }
37+
public void Dispose() { throw null; }
38+
System.Collections.Generic.IDictionary<string, object> IConfigurationBuilder.Properties { get { throw null; } }
39+
System.Collections.Generic.IList<Microsoft.Extensions.Configuration.IConfigurationSource> IConfigurationBuilder.Sources { get { throw null; } }
40+
Microsoft.Extensions.Configuration.IConfigurationBuilder IConfigurationBuilder.Add(Microsoft.Extensions.Configuration.IConfigurationSource source) { throw null; }
41+
Microsoft.Extensions.Configuration.IConfigurationRoot IConfigurationBuilder.Build() { throw null; }
42+
System.Collections.Generic.IEnumerable<IConfigurationProvider> IConfigurationRoot.Providers { get { throw null; } }
43+
void IConfigurationRoot.Reload() { throw null; }
44+
Primitives.IChangeToken IConfiguration.GetReloadToken() { throw null; }
45+
}
3146
public partial class ConfigurationBuilder : Microsoft.Extensions.Configuration.IConfigurationBuilder
3247
{
3348
public ConfigurationBuilder() { }
Lines changed: 353 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,353 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
using System.Collections;
6+
using System.Collections.Generic;
7+
using System.Linq;
8+
using System.Threading;
9+
using Microsoft.Extensions.Primitives;
10+
11+
namespace Microsoft.Extensions.Configuration
12+
{
13+
/// <summary>
14+
/// Configuration is mutable configuration object. It is both an <see cref="IConfigurationBuilder"/> and an <see cref="IConfigurationRoot"/>.
15+
/// As sources are added, it updates its current view of configuration. Once Build is called, configuration is frozen.
16+
/// </summary>
17+
public sealed class ConfigurationManager : IConfigurationBuilder, IConfigurationRoot, IDisposable
18+
{
19+
private readonly ConfigurationSources _sources;
20+
private readonly ConfigurationBuilderProperties _properties;
21+
22+
private readonly object _providerLock = new();
23+
private readonly List<IConfigurationProvider> _providers = new();
24+
private readonly List<IDisposable> _changeTokenRegistrations = new();
25+
private ConfigurationReloadToken _changeToken = new();
26+
27+
/// <summary>
28+
/// Creates an empty mutable configuration object that is both an <see cref="IConfigurationBuilder"/> and an <see cref="IConfigurationRoot"/>.
29+
/// </summary>
30+
public ConfigurationManager()
31+
{
32+
_sources = new ConfigurationSources(this);
33+
_properties = new ConfigurationBuilderProperties(this);
34+
35+
// Make sure there's some default storage since there are no default providers.
36+
this.AddInMemoryCollection();
37+
38+
AddSource(_sources[0]);
39+
}
40+
41+
/// <inheritdoc/>
42+
public string this[string key]
43+
{
44+
get
45+
{
46+
lock (_providerLock)
47+
{
48+
return ConfigurationRoot.GetConfiguration(_providers, key);
49+
}
50+
}
51+
set
52+
{
53+
lock (_providerLock)
54+
{
55+
ConfigurationRoot.SetConfiguration(_providers, key, value);
56+
}
57+
}
58+
}
59+
60+
/// <inheritdoc/>
61+
public IConfigurationSection GetSection(string key) => new ConfigurationSection(this, key);
62+
63+
/// <inheritdoc/>
64+
public IEnumerable<IConfigurationSection> GetChildren()
65+
{
66+
lock (_providerLock)
67+
{
68+
// ToList() to eagerly evaluate inside lock.
69+
return this.GetChildrenImplementation(null).ToList();
70+
}
71+
}
72+
73+
IDictionary<string, object> IConfigurationBuilder.Properties => _properties;
74+
75+
IList<IConfigurationSource> IConfigurationBuilder.Sources => _sources;
76+
77+
IEnumerable<IConfigurationProvider> IConfigurationRoot.Providers
78+
{
79+
get
80+
{
81+
lock (_providerLock)
82+
{
83+
return new List<IConfigurationProvider>(_providers);
84+
}
85+
}
86+
}
87+
88+
/// <inheritdoc/>
89+
public void Dispose()
90+
{
91+
lock (_providerLock)
92+
{
93+
DisposeRegistrationsAndProvidersUnsynchronized();
94+
}
95+
}
96+
97+
IConfigurationBuilder IConfigurationBuilder.Add(IConfigurationSource source)
98+
{
99+
_sources.Add(source ?? throw new ArgumentNullException(nameof(source)));
100+
return this;
101+
}
102+
103+
IConfigurationRoot IConfigurationBuilder.Build() => this;
104+
105+
IChangeToken IConfiguration.GetReloadToken() => _changeToken;
106+
107+
void IConfigurationRoot.Reload()
108+
{
109+
lock (_providerLock)
110+
{
111+
foreach (var provider in _providers)
112+
{
113+
provider.Load();
114+
}
115+
}
116+
117+
RaiseChanged();
118+
}
119+
120+
private void RaiseChanged()
121+
{
122+
var previousToken = Interlocked.Exchange(ref _changeToken, new ConfigurationReloadToken());
123+
previousToken.OnReload();
124+
}
125+
126+
// Don't rebuild and reload all providers in the common case when a source is simply added to the IList.
127+
private void AddSource(IConfigurationSource source)
128+
{
129+
lock (_providerLock)
130+
{
131+
var provider = source.Build(this);
132+
_providers.Add(provider);
133+
134+
provider.Load();
135+
_changeTokenRegistrations.Add(ChangeToken.OnChange(() => provider.GetReloadToken(), () => RaiseChanged()));
136+
}
137+
138+
RaiseChanged();
139+
}
140+
141+
// Something other than Add was called on IConfigurationBuilder.Sources or IConfigurationBuilder.Properties has changed.
142+
private void ReloadSources()
143+
{
144+
lock (_providerLock)
145+
{
146+
DisposeRegistrationsAndProvidersUnsynchronized();
147+
148+
_changeTokenRegistrations.Clear();
149+
_providers.Clear();
150+
151+
foreach (var source in _sources)
152+
{
153+
_providers.Add(source.Build(this));
154+
}
155+
156+
foreach (var p in _providers)
157+
{
158+
p.Load();
159+
_changeTokenRegistrations.Add(ChangeToken.OnChange(() => p.GetReloadToken(), () => RaiseChanged()));
160+
}
161+
}
162+
163+
RaiseChanged();
164+
}
165+
166+
private void DisposeRegistrationsAndProvidersUnsynchronized()
167+
{
168+
// dispose change token registrations
169+
foreach (var registration in _changeTokenRegistrations)
170+
{
171+
registration.Dispose();
172+
}
173+
174+
// dispose providers
175+
foreach (var provider in _providers)
176+
{
177+
(provider as IDisposable)?.Dispose();
178+
}
179+
}
180+
181+
private class ConfigurationSources : IList<IConfigurationSource>
182+
{
183+
private readonly List<IConfigurationSource> _sources = new();
184+
private readonly ConfigurationManager _config;
185+
186+
public ConfigurationSources(ConfigurationManager config)
187+
{
188+
_config = config;
189+
}
190+
191+
public IConfigurationSource this[int index]
192+
{
193+
get => _sources[index];
194+
set
195+
{
196+
_sources[index] = value;
197+
_config.ReloadSources();
198+
}
199+
}
200+
201+
public int Count => _sources.Count;
202+
203+
public bool IsReadOnly => false;
204+
205+
public void Add(IConfigurationSource source)
206+
{
207+
_sources.Add(source);
208+
_config.AddSource(source);
209+
}
210+
211+
public void Clear()
212+
{
213+
_sources.Clear();
214+
_config.ReloadSources();
215+
}
216+
217+
public bool Contains(IConfigurationSource source)
218+
{
219+
return _sources.Contains(source);
220+
}
221+
222+
public void CopyTo(IConfigurationSource[] array, int arrayIndex)
223+
{
224+
_sources.CopyTo(array, arrayIndex);
225+
}
226+
227+
public IEnumerator<IConfigurationSource> GetEnumerator()
228+
{
229+
return _sources.GetEnumerator();
230+
}
231+
232+
public int IndexOf(IConfigurationSource source)
233+
{
234+
return _sources.IndexOf(source);
235+
}
236+
237+
public void Insert(int index, IConfigurationSource source)
238+
{
239+
_sources.Insert(index, source);
240+
_config.ReloadSources();
241+
}
242+
243+
public bool Remove(IConfigurationSource source)
244+
{
245+
var removed = _sources.Remove(source);
246+
_config.ReloadSources();
247+
return removed;
248+
}
249+
250+
public void RemoveAt(int index)
251+
{
252+
_sources.RemoveAt(index);
253+
_config.ReloadSources();
254+
}
255+
256+
IEnumerator IEnumerable.GetEnumerator()
257+
{
258+
return GetEnumerator();
259+
}
260+
}
261+
262+
private class ConfigurationBuilderProperties : IDictionary<string, object>
263+
{
264+
private readonly Dictionary<string, object> _properties = new();
265+
private readonly ConfigurationManager _config;
266+
267+
public ConfigurationBuilderProperties(ConfigurationManager config)
268+
{
269+
_config = config;
270+
}
271+
272+
public object this[string key]
273+
{
274+
get => _properties[key];
275+
set
276+
{
277+
_properties[key] = value;
278+
_config.ReloadSources();
279+
}
280+
}
281+
282+
public ICollection<string> Keys => _properties.Keys;
283+
284+
public ICollection<object> Values => _properties.Values;
285+
286+
public int Count => _properties.Count;
287+
288+
public bool IsReadOnly => false;
289+
290+
public void Add(string key, object value)
291+
{
292+
_properties.Add(key, value);
293+
_config.ReloadSources();
294+
}
295+
296+
public void Add(KeyValuePair<string, object> item)
297+
{
298+
((IDictionary<string, object>)_properties).Add(item);
299+
_config.ReloadSources();
300+
}
301+
302+
public void Clear()
303+
{
304+
_properties.Clear();
305+
_config.ReloadSources();
306+
}
307+
308+
public bool Contains(KeyValuePair<string, object> item)
309+
{
310+
return _properties.Contains(item);
311+
}
312+
313+
public bool ContainsKey(string key)
314+
{
315+
return _properties.ContainsKey(key);
316+
}
317+
318+
public void CopyTo(KeyValuePair<string, object>[] array, int arrayIndex)
319+
{
320+
((IDictionary<string, object>)_properties).CopyTo(array, arrayIndex);
321+
}
322+
323+
public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
324+
{
325+
return _properties.GetEnumerator();
326+
}
327+
328+
public bool Remove(string key)
329+
{
330+
var wasRemoved = _properties.Remove(key);
331+
_config.ReloadSources();
332+
return wasRemoved;
333+
}
334+
335+
public bool Remove(KeyValuePair<string, object> item)
336+
{
337+
var wasRemoved = ((IDictionary<string, object>)_properties).Remove(item);
338+
_config.ReloadSources();
339+
return wasRemoved;
340+
}
341+
342+
public bool TryGetValue(string key, out object value)
343+
{
344+
return _properties.TryGetValue(key, out value);
345+
}
346+
347+
IEnumerator IEnumerable.GetEnumerator()
348+
{
349+
return _properties.GetEnumerator();
350+
}
351+
}
352+
}
353+
}

0 commit comments

Comments
 (0)