Skip to content

Commit 39273cd

Browse files
authored
Merge branch 'release/2.2' into merge/release/2.1-to-release/2.2\n\nCommit migrated from dotnet/extensions@a83df95
2 parents 3db4f50 + 468f1ff commit 39273cd

File tree

100 files changed

+6164
-50
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

100 files changed

+6164
-50
lines changed

src/Configuration.KeyPerFile/src/KeyPerFileConfigurationProvider.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,13 @@ private static string TrimNewLine(string value)
3131
/// </summary>
3232
public override void Load()
3333
{
34-
Data = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
34+
var data = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
3535

3636
if (Source.FileProvider == null)
3737
{
3838
if (Source.Optional)
3939
{
40+
Data = data;
4041
return;
4142
}
4243
else
@@ -63,10 +64,12 @@ public override void Load()
6364
{
6465
if (Source.IgnoreCondition == null || !Source.IgnoreCondition(file.Name))
6566
{
66-
Data.Add(NormalizeKey(file.Name), TrimNewLine(streamReader.ReadToEnd()));
67+
data.Add(NormalizeKey(file.Name), TrimNewLine(streamReader.ReadToEnd()));
6768
}
6869
}
6970
}
71+
72+
Data = data;
7073
}
7174
}
7275
}

src/Configuration.KeyPerFile/test/KeyPerFileTests.cs

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
using System.IO;
55
using System.Linq;
66
using System.Text;
7+
using System.Threading;
8+
using System.Threading.Tasks;
79
using Microsoft.Extensions.FileProviders;
810
using Microsoft.Extensions.Primitives;
911
using Xunit;
@@ -28,7 +30,7 @@ public void DoesNotThrowWhenOptionalAndDirectoryDoesntExist()
2830
public void ThrowsWhenNotOptionalAndDirectoryDoesntExist()
2931
{
3032
var e = Assert.Throws<ArgumentException>(() => new ConfigurationBuilder().AddKeyPerFile("nonexistent", false).Build());
31-
Assert.Contains("The directory name", e.Message);
33+
Assert.Contains("The path must be absolute.", e.Message);
3234
}
3335

3436
[Fact]
@@ -177,6 +179,39 @@ public void CanUnIgnoreDefaultFiles()
177179
Assert.Equal("SecretValue1", config["ignore.Secret1"]);
178180
Assert.Equal("SecretValue2", config["Secret2"]);
179181
}
182+
183+
[Fact]
184+
public void BindingDoesNotThrowIfReloadedDuringBinding()
185+
{
186+
var testFileProvider = new TestFileProvider(
187+
new TestFile("Number", "-2"),
188+
new TestFile("Text", "Foo"));
189+
190+
var config = new ConfigurationBuilder()
191+
.AddKeyPerFile(o => o.FileProvider = testFileProvider)
192+
.Build();
193+
194+
MyOptions options = null;
195+
196+
using (var cts = new CancellationTokenSource(TimeSpan.FromMilliseconds(250)))
197+
{
198+
_ = Task.Run(() => { while (!cts.IsCancellationRequested) config.Reload(); });
199+
200+
while (!cts.IsCancellationRequested)
201+
{
202+
options = config.Get<MyOptions>();
203+
}
204+
}
205+
206+
Assert.Equal(-2, options.Number);
207+
Assert.Equal("Foo", options.Text);
208+
}
209+
210+
private sealed class MyOptions
211+
{
212+
public int Number { get; set; }
213+
public string Text { get; set; }
214+
}
180215
}
181216

182217
class TestFileProvider : IFileProvider
@@ -305,4 +340,4 @@ public Stream CreateReadStream()
305340
return new MemoryStream(Encoding.UTF8.GetBytes(_contents));
306341
}
307342
}
308-
}
343+
}

src/Configuration.KeyPerFile/test/Microsoft.Extensions.Configuration.KeyPerFile.Tests.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<TargetFrameworks>netcoreapp2.1;net461</TargetFrameworks>
4+
<TargetFrameworks>netcoreapp2.2;net461</TargetFrameworks>
55
</PropertyGroup>
66

77
<ItemGroup>
8+
<Reference Include="Microsoft.Extensions.Configuration.Binder" />
89
<Reference Include="Microsoft.Extensions.Configuration.KeyPerFile" />
910
</ItemGroup>
1011

src/FileProviders/Embedded/src/Microsoft.Extensions.FileProviders.Embedded.csproj

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@
1212
<ProjectReference Include="..\..\Manifest.MSBuildTask\src\Microsoft.Extensions.FileProviders.Embedded.Manifest.Task.csproj" PrivateAssets="All" ReferenceOutputAssembly="false" />
1313
</ItemGroup>
1414

15+
<ItemGroup>
16+
<SignedPackageFile Include="$(TargetPath)" Certificate="$(AssemblySigningCertName)" />
17+
<SignedPackageFile Include="Microsoft.Extensions.FileProviders.Embedded.Manifest.Task.dll" Certificate="$(AssemblySigningCertName)" />
18+
</ItemGroup>
19+
1520
<Target Name="PopulateNuspec" BeforeTargets="GenerateNuspec" DependsOnTargets="BuiltProjectOutputGroup;DocumentationProjectOutputGroup;DebugSymbolsProjectOutputGroup;">
1621

1722
<PropertyGroup>

src/FileProviders/Embedded/test/Microsoft.Extensions.FileProviders.Embedded.Tests.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<TargetFrameworks>netcoreapp2.1;net461</TargetFrameworks>
4+
<TargetFrameworks>netcoreapp2.2;net461</TargetFrameworks>
55
</PropertyGroup>
66

77
<ItemGroup>

src/FileProviders/Manifest.MSBuildTask/test/Microsoft.Extensions.FileProviders.Embedded.Manifest.Task.Test.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<TargetFrameworks>netcoreapp2.1;net461</TargetFrameworks>
4+
<TargetFrameworks>netcoreapp2.2;net461</TargetFrameworks>
55
</PropertyGroup>
66

77
<ItemGroup>
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<Project>
2+
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory)..\, Directory.Build.props))\Directory.Build.props" />
3+
4+
<PropertyGroup>
5+
<IsProductComponent>true</IsProductComponent>
6+
</PropertyGroup>
7+
</Project>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
namespace Microsoft.Extensions.Diagnostics.HealthChecks
5+
{
6+
public sealed class HealthCheckContext
7+
{
8+
/// <summary>
9+
/// Gets or sets the <see cref="HealthCheckRegistration"/> of the currently executing <see cref="IHealthCheck"/>.
10+
/// </summary>
11+
public HealthCheckRegistration Registration { get; set; }
12+
}
13+
}
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
7+
namespace Microsoft.Extensions.Diagnostics.HealthChecks
8+
{
9+
/// <summary>
10+
/// Represent the registration information associated with an <see cref="IHealthCheck"/> implementation.
11+
/// </summary>
12+
/// <remarks>
13+
/// <para>
14+
/// The health check registration is provided as a separate object so that application developers can customize
15+
/// how health check implementations are configured.
16+
/// </para>
17+
/// <para>
18+
/// The registration is provided to an <see cref="IHealthCheck"/> implementation during execution through
19+
/// <see cref="HealthCheckContext.Registration"/>. This allows a health check implementation to access named
20+
/// options or perform other operations based on the registered name.
21+
/// </para>
22+
/// </remarks>
23+
public sealed class HealthCheckRegistration
24+
{
25+
private Func<IServiceProvider, IHealthCheck> _factory;
26+
private string _name;
27+
28+
/// <summary>
29+
/// Creates a new <see cref="HealthCheckRegistration"/> for an existing <see cref="IHealthCheck"/> instance.
30+
/// </summary>
31+
/// <param name="name">The health check name.</param>
32+
/// <param name="instance">The <see cref="IHealthCheck"/> instance.</param>
33+
/// <param name="failureStatus">
34+
/// The <see cref="HealthStatus"/> that should be reported upon failure of the health check. If the provided value
35+
/// is <c>null</c>, then <see cref="HealthStatus.Unhealthy"/> will be reported.
36+
/// </param>
37+
/// <param name="tags">A list of tags that can be used for filtering health checks.</param>
38+
public HealthCheckRegistration(string name, IHealthCheck instance, HealthStatus? failureStatus, IEnumerable<string> tags)
39+
{
40+
if (name == null)
41+
{
42+
throw new ArgumentNullException(nameof(name));
43+
}
44+
45+
if (instance == null)
46+
{
47+
throw new ArgumentNullException(nameof(instance));
48+
}
49+
50+
Name = name;
51+
FailureStatus = failureStatus ?? HealthStatus.Unhealthy;
52+
Tags = new HashSet<string>(tags ?? Array.Empty<string>(), StringComparer.OrdinalIgnoreCase);
53+
Factory = (_) => instance;
54+
}
55+
56+
/// <summary>
57+
/// Creates a new <see cref="HealthCheckRegistration"/> for an existing <see cref="IHealthCheck"/> instance.
58+
/// </summary>
59+
/// <param name="name">The health check name.</param>
60+
/// <param name="factory">A delegate used to create the <see cref="IHealthCheck"/> instance.</param>
61+
/// <param name="failureStatus">
62+
/// The <see cref="HealthStatus"/> that should be reported when the health check reports a failure. If the provided value
63+
/// is <c>null</c>, then <see cref="HealthStatus.Unhealthy"/> will be reported.
64+
/// </param>
65+
/// <param name="tags">A list of tags that can be used for filtering health checks.</param>
66+
public HealthCheckRegistration(
67+
string name,
68+
Func<IServiceProvider, IHealthCheck> factory,
69+
HealthStatus? failureStatus,
70+
IEnumerable<string> tags)
71+
{
72+
if (name == null)
73+
{
74+
throw new ArgumentNullException(nameof(name));
75+
}
76+
77+
if (factory == null)
78+
{
79+
throw new ArgumentNullException(nameof(factory));
80+
}
81+
82+
Name = name;
83+
FailureStatus = failureStatus ?? HealthStatus.Unhealthy;
84+
Tags = new HashSet<string>(tags ?? Array.Empty<string>(), StringComparer.OrdinalIgnoreCase);
85+
Factory = factory;
86+
}
87+
88+
/// <summary>
89+
/// Gets or sets a delegate used to create the <see cref="IHealthCheck"/> instance.
90+
/// </summary>
91+
public Func<IServiceProvider, IHealthCheck> Factory
92+
{
93+
get => _factory;
94+
set
95+
{
96+
if (value == null)
97+
{
98+
throw new ArgumentNullException(nameof(value));
99+
}
100+
101+
_factory = value;
102+
}
103+
}
104+
105+
/// <summary>
106+
/// Gets or sets the <see cref="HealthStatus"/> that should be reported upon failure of the health check.
107+
/// </summary>
108+
public HealthStatus FailureStatus { get; set; }
109+
110+
/// <summary>
111+
/// Gets or sets the health check name.
112+
/// </summary>
113+
public string Name
114+
{
115+
get => _name;
116+
set
117+
{
118+
if (value == null)
119+
{
120+
throw new ArgumentNullException(nameof(value));
121+
}
122+
123+
_name = value;
124+
}
125+
}
126+
127+
/// <summary>
128+
/// Gets a list of tags that can be used for filtering health checks.
129+
/// </summary>
130+
public ISet<string> Tags { get; }
131+
}
132+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
7+
namespace Microsoft.Extensions.Diagnostics.HealthChecks
8+
{
9+
/// <summary>
10+
/// Represents the result of a health check.
11+
/// </summary>
12+
public struct HealthCheckResult
13+
{
14+
private static readonly IReadOnlyDictionary<string, object> _emptyReadOnlyDictionary = new Dictionary<string, object>();
15+
16+
/// <summary>
17+
/// Creates a new <see cref="HealthCheckResult"/> with the specified values for <paramref name="status"/>,
18+
/// <paramref name="exception"/>, <paramref name="description"/>, and <paramref name="data"/>.
19+
/// </summary>
20+
/// <param name="status">A value indicating the status of the component that was checked.</param>
21+
/// <param name="description">A human-readable description of the status of the component that was checked.</param>
22+
/// <param name="exception">An <see cref="Exception"/> representing the exception that was thrown when checking for status (if any).</param>
23+
/// <param name="data">Additional key-value pairs describing the health of the component.</param>
24+
public HealthCheckResult(HealthStatus status, string description = null, Exception exception = null, IReadOnlyDictionary<string, object> data = null)
25+
{
26+
Status = status;
27+
Description = description;
28+
Exception = exception;
29+
Data = data ?? _emptyReadOnlyDictionary;
30+
}
31+
32+
/// <summary>
33+
/// Gets additional key-value pairs describing the health of the component.
34+
/// </summary>
35+
public IReadOnlyDictionary<string, object> Data { get; }
36+
37+
/// <summary>
38+
/// Gets a human-readable description of the status of the component that was checked.
39+
/// </summary>
40+
public string Description { get; }
41+
42+
/// <summary>
43+
/// Gets an <see cref="Exception"/> representing the exception that was thrown when checking for status (if any).
44+
/// </summary>
45+
public Exception Exception { get; }
46+
47+
/// <summary>
48+
/// Gets a value indicating the status of the component that was checked.
49+
/// </summary>
50+
public HealthStatus Status { get; }
51+
52+
/// <summary>
53+
/// Creates a <see cref="HealthCheckResult"/> representing a healthy component.
54+
/// </summary>
55+
/// <param name="description">A human-readable description of the status of the component that was checked. Optional.</param>
56+
/// <param name="data">Additional key-value pairs describing the health of the component. Optional.</param>
57+
/// <returns>A <see cref="HealthCheckResult"/> representing a healthy component.</returns>
58+
public static HealthCheckResult Healthy(string description = null, IReadOnlyDictionary<string, object> data = null)
59+
{
60+
return new HealthCheckResult(status: HealthStatus.Healthy, description, exception: null, data);
61+
}
62+
63+
64+
/// <summary>
65+
/// Creates a <see cref="HealthCheckResult"/> representing a degraded component.
66+
/// </summary>
67+
/// <param name="description">A human-readable description of the status of the component that was checked. Optional.</param>
68+
/// <param name="exception">An <see cref="Exception"/> representing the exception that was thrown when checking for status. Optional.</param>
69+
/// <param name="data">Additional key-value pairs describing the health of the component. Optional.</param>
70+
/// <returns>A <see cref="HealthCheckResult"/> representing a degraged component.</returns>
71+
public static HealthCheckResult Degraded(string description = null, Exception exception = null, IReadOnlyDictionary<string, object> data = null)
72+
{
73+
return new HealthCheckResult(status: HealthStatus.Degraded, description, exception: null, data);
74+
}
75+
76+
/// <summary>
77+
/// Creates a <see cref="HealthCheckResult"/> representing an unhealthy component.
78+
/// </summary>
79+
/// <param name="description">A human-readable description of the status of the component that was checked. Optional.</param>
80+
/// <param name="exception">An <see cref="Exception"/> representing the exception that was thrown when checking for status. Optional.</param>
81+
/// <param name="data">Additional key-value pairs describing the health of the component. Optional.</param>
82+
/// <returns>A <see cref="HealthCheckResult"/> representing an unhealthy component.</returns>
83+
public static HealthCheckResult Unhealthy(string description = null, Exception exception = null, IReadOnlyDictionary<string, object> data = null)
84+
{
85+
return new HealthCheckResult(status: HealthStatus.Unhealthy, description, exception, data);
86+
}
87+
}
88+
}

0 commit comments

Comments
 (0)