diff --git a/src/Configuration.KeyPerFile/Directory.Build.props b/src/Configuration.KeyPerFile/Directory.Build.props
index 2082380096..63d0c8b102 100644
--- a/src/Configuration.KeyPerFile/Directory.Build.props
+++ b/src/Configuration.KeyPerFile/Directory.Build.props
@@ -2,7 +2,8 @@
- true
+ true
configuration
+ $(NoWarn);PKG0001
diff --git a/src/Configuration.KeyPerFile/ref/Microsoft.Extensions.Configuration.KeyPerFile.csproj b/src/Configuration.KeyPerFile/ref/Microsoft.Extensions.Configuration.KeyPerFile.csproj
new file mode 100644
index 0000000000..21f0053e59
--- /dev/null
+++ b/src/Configuration.KeyPerFile/ref/Microsoft.Extensions.Configuration.KeyPerFile.csproj
@@ -0,0 +1,11 @@
+
+
+
+ netstandard2.0
+
+
+
+
+
+
+
diff --git a/src/Configuration.KeyPerFile/ref/Microsoft.Extensions.Configuration.KeyPerFile.netstandard2.0.cs b/src/Configuration.KeyPerFile/ref/Microsoft.Extensions.Configuration.KeyPerFile.netstandard2.0.cs
new file mode 100644
index 0000000000..e26ca1909d
--- /dev/null
+++ b/src/Configuration.KeyPerFile/ref/Microsoft.Extensions.Configuration.KeyPerFile.netstandard2.0.cs
@@ -0,0 +1,29 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Microsoft.Extensions.Configuration
+{
+ public static partial class KeyPerFileConfigurationBuilderExtensions
+ {
+ public static Microsoft.Extensions.Configuration.IConfigurationBuilder AddKeyPerFile(this Microsoft.Extensions.Configuration.IConfigurationBuilder builder, System.Action configureSource) { throw null; }
+ public static Microsoft.Extensions.Configuration.IConfigurationBuilder AddKeyPerFile(this Microsoft.Extensions.Configuration.IConfigurationBuilder builder, string directoryPath, bool optional) { throw null; }
+ }
+}
+namespace Microsoft.Extensions.Configuration.KeyPerFile
+{
+ public partial class KeyPerFileConfigurationProvider : Microsoft.Extensions.Configuration.ConfigurationProvider
+ {
+ public KeyPerFileConfigurationProvider(Microsoft.Extensions.Configuration.KeyPerFile.KeyPerFileConfigurationSource source) { }
+ public override void Load() { }
+ public override string ToString() { throw null; }
+ }
+ public partial class KeyPerFileConfigurationSource : Microsoft.Extensions.Configuration.IConfigurationSource
+ {
+ public KeyPerFileConfigurationSource() { }
+ public Microsoft.Extensions.FileProviders.IFileProvider FileProvider { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
+ public System.Func IgnoreCondition { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
+ public string IgnorePrefix { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
+ public bool Optional { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
+ public Microsoft.Extensions.Configuration.IConfigurationProvider Build(Microsoft.Extensions.Configuration.IConfigurationBuilder builder) { throw null; }
+ }
+}
diff --git a/src/Configuration.KeyPerFile/src/KeyPerFileConfigurationProvider.cs b/src/Configuration.KeyPerFile/src/KeyPerFileConfigurationProvider.cs
index 6e4234ecf3..2e33b9dfcd 100644
--- a/src/Configuration.KeyPerFile/src/KeyPerFileConfigurationProvider.cs
+++ b/src/Configuration.KeyPerFile/src/KeyPerFileConfigurationProvider.cs
@@ -40,10 +40,8 @@ namespace Microsoft.Extensions.Configuration.KeyPerFile
Data = data;
return;
}
- else
- {
- throw new DirectoryNotFoundException("A non-null file provider for the directory is required when this source is not optional.");
- }
+
+ throw new DirectoryNotFoundException("A non-null file provider for the directory is required when this source is not optional.");
}
var directory = Source.FileProvider.GetDirectoryContents("/");
@@ -71,5 +69,15 @@ namespace Microsoft.Extensions.Configuration.KeyPerFile
Data = data;
}
+
+ private string GetDirectoryName()
+ => Source.FileProvider?.GetFileInfo("/")?.PhysicalPath ?? "";
+
+ ///
+ /// Generates a string representing this provider name and relevant details.
+ ///
+ /// The configuration name.
+ public override string ToString()
+ => $"{GetType().Name} for files in '{GetDirectoryName()}' ({(Source.Optional ? "Optional" : "Required")})";
}
}
diff --git a/src/Configuration.KeyPerFile/src/Microsoft.Extensions.Configuration.KeyPerFile.csproj b/src/Configuration.KeyPerFile/src/Microsoft.Extensions.Configuration.KeyPerFile.csproj
index 4eb19f3293..5bd7b2c7ef 100644
--- a/src/Configuration.KeyPerFile/src/Microsoft.Extensions.Configuration.KeyPerFile.csproj
+++ b/src/Configuration.KeyPerFile/src/Microsoft.Extensions.Configuration.KeyPerFile.csproj
@@ -3,7 +3,7 @@
Configuration provider that uses files in a directory for Microsoft.Extensions.Configuration.
netstandard2.0
- false
+ true
diff --git a/src/Configuration.KeyPerFile/test/ConfigurationProviderCommandLineTest.cs b/src/Configuration.KeyPerFile/test/ConfigurationProviderCommandLineTest.cs
new file mode 100644
index 0000000000..066aecf337
--- /dev/null
+++ b/src/Configuration.KeyPerFile/test/ConfigurationProviderCommandLineTest.cs
@@ -0,0 +1,43 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Microsoft.Extensions.Configuration.Test;
+using Microsoft.Extensions.FileProviders;
+
+namespace Microsoft.Extensions.Configuration.KeyPerFile.Test
+{
+ public class ConfigurationProviderCommandLineTest : ConfigurationProviderTestBase
+ {
+ protected override (IConfigurationProvider Provider, Action Initializer) LoadThroughProvider(
+ TestSection testConfig)
+ {
+ var testFiles = new List();
+ SectionToTestFiles(testFiles, "", testConfig);
+
+ var provider = new KeyPerFileConfigurationProvider(
+ new KeyPerFileConfigurationSource
+ {
+ Optional = true,
+ FileProvider = new TestFileProvider(testFiles.ToArray())
+ });
+
+ return (provider, () => { });
+ }
+
+ private void SectionToTestFiles(List testFiles, string sectionName, TestSection section)
+ {
+ foreach (var tuple in section.Values.SelectMany(e => e.Value.Expand(e.Key)))
+ {
+ testFiles.Add(new TestFile(sectionName + tuple.Key, tuple.Value));
+ }
+
+ foreach (var tuple in section.Sections)
+ {
+ SectionToTestFiles(testFiles, sectionName + tuple.Key + "__", tuple.Section);
+ }
+ }
+ }
+}
diff --git a/src/Configuration.KeyPerFile/test/ConfigurationProviderTestBase.cs b/src/Configuration.KeyPerFile/test/ConfigurationProviderTestBase.cs
new file mode 100644
index 0000000000..4609ee2560
--- /dev/null
+++ b/src/Configuration.KeyPerFile/test/ConfigurationProviderTestBase.cs
@@ -0,0 +1,761 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Microsoft.Extensions.Configuration.Memory;
+using Xunit;
+
+namespace Microsoft.Extensions.Configuration.Test
+{
+ public abstract class ConfigurationProviderTestBase
+ {
+ [Fact]
+ public virtual void Load_from_single_provider()
+ {
+ var configRoot = BuildConfigRoot(LoadThroughProvider(TestSection.TestConfig));
+
+ AssertConfig(configRoot);
+ }
+
+ [Fact]
+ public virtual void Has_debug_view()
+ {
+ var configRoot = BuildConfigRoot(LoadThroughProvider(TestSection.TestConfig));
+ var providerTag = configRoot.Providers.Single().ToString();
+
+ var expected =
+ $@"Key1=Value1 ({providerTag})
+Section1:
+ Key2=Value12 ({providerTag})
+ Section2:
+ Key3=Value123 ({providerTag})
+ Key3a:
+ 0=ArrayValue0 ({providerTag})
+ 1=ArrayValue1 ({providerTag})
+ 2=ArrayValue2 ({providerTag})
+Section3:
+ Section4:
+ Key4=Value344 ({providerTag})
+";
+
+ AssertDebugView(configRoot, expected);
+ }
+
+ [Fact]
+ public virtual void Null_values_are_included_in_the_config()
+ {
+ AssertConfig(BuildConfigRoot(LoadThroughProvider(TestSection.NullsTestConfig)), expectNulls: true, nullValue: "");
+ }
+
+ [Fact]
+ public virtual void Combine_after_other_provider()
+ {
+ AssertConfig(
+ BuildConfigRoot(
+ LoadUsingMemoryProvider(TestSection.MissingSection2ValuesConfig),
+ LoadThroughProvider(TestSection.MissingSection4Config)));
+
+ AssertConfig(
+ BuildConfigRoot(
+ LoadUsingMemoryProvider(TestSection.MissingSection4Config),
+ LoadThroughProvider(TestSection.MissingSection2ValuesConfig)));
+ }
+
+ [Fact]
+ public virtual void Combine_before_other_provider()
+ {
+ AssertConfig(
+ BuildConfigRoot(
+ LoadThroughProvider(TestSection.MissingSection2ValuesConfig),
+ LoadUsingMemoryProvider(TestSection.MissingSection4Config)));
+
+ AssertConfig(
+ BuildConfigRoot(
+ LoadThroughProvider(TestSection.MissingSection4Config),
+ LoadUsingMemoryProvider(TestSection.MissingSection2ValuesConfig)));
+ }
+
+ [Fact]
+ public virtual void Second_provider_overrides_values_from_first()
+ {
+ AssertConfig(
+ BuildConfigRoot(
+ LoadUsingMemoryProvider(TestSection.NoValuesTestConfig),
+ LoadThroughProvider(TestSection.TestConfig)));
+ }
+
+ [Fact]
+ public virtual void Combining_from_multiple_providers_is_case_insensitive()
+ {
+ AssertConfig(
+ BuildConfigRoot(
+ LoadUsingMemoryProvider(TestSection.DifferentCasedTestConfig),
+ LoadThroughProvider(TestSection.TestConfig)));
+ }
+
+ [Fact]
+ public virtual void Load_from_single_provider_with_duplicates_throws()
+ {
+ AssertFormatOrArgumentException(
+ () => BuildConfigRoot(LoadThroughProvider(TestSection.DuplicatesTestConfig)));
+ }
+
+ [Fact]
+ public virtual void Load_from_single_provider_with_differing_case_duplicates_throws()
+ {
+ AssertFormatOrArgumentException(
+ () => BuildConfigRoot(LoadThroughProvider(TestSection.DuplicatesDifferentCaseTestConfig)));
+ }
+
+ private void AssertFormatOrArgumentException(Action test)
+ {
+ Exception caught = null;
+ try
+ {
+ test();
+ }
+ catch (Exception e)
+ {
+ caught = e;
+ }
+
+ Assert.True(caught is ArgumentException
+ || caught is FormatException);
+ }
+
+ [Fact]
+ public virtual void Bind_to_object()
+ {
+ var configuration = BuildConfigRoot(LoadThroughProvider(TestSection.TestConfig));
+
+ var options = configuration.Get();
+
+ Assert.Equal("Value1", options.Key1);
+ Assert.Equal("Value12", options.Section1.Key2);
+ Assert.Equal("Value123", options.Section1.Section2.Key3);
+ Assert.Equal("Value344", options.Section3.Section4.Key4);
+ Assert.Equal(new[] { "ArrayValue0", "ArrayValue1", "ArrayValue2" }, options.Section1.Section2.Key3a);
+ }
+
+ public class AsOptions
+ {
+ public string Key1 { get; set; }
+
+ public Section1AsOptions Section1 { get; set; }
+ public Section3AsOptions Section3 { get; set; }
+ }
+
+ public class Section1AsOptions
+ {
+ public string Key2 { get; set; }
+
+ public Section2AsOptions Section2 { get; set; }
+ }
+
+ public class Section2AsOptions
+ {
+ public string Key3 { get; set; }
+ public string[] Key3a { get; set; }
+ }
+
+ public class Section3AsOptions
+ {
+ public Section4AsOptions Section4 { get; set; }
+ }
+
+ public class Section4AsOptions
+ {
+ public string Key4 { get; set; }
+ }
+
+ protected virtual void AssertDebugView(
+ IConfigurationRoot config,
+ string expected)
+ {
+ string RemoveLineEnds(string source) => source.Replace("\n", "").Replace("\r", "");
+
+ var actual = config.GetDebugView();
+
+ Assert.Equal(
+ RemoveLineEnds(expected),
+ RemoveLineEnds(actual));
+ }
+
+ protected virtual void AssertConfig(
+ IConfigurationRoot config,
+ bool expectNulls = false,
+ string nullValue = null)
+ {
+ var value1 = expectNulls ? nullValue : "Value1";
+ var value12 = expectNulls ? nullValue : "Value12";
+ var value123 = expectNulls ? nullValue : "Value123";
+ var arrayvalue0 = expectNulls ? nullValue : "ArrayValue0";
+ var arrayvalue1 = expectNulls ? nullValue : "ArrayValue1";
+ var arrayvalue2 = expectNulls ? nullValue : "ArrayValue2";
+ var value344 = expectNulls ? nullValue : "Value344";
+
+ Assert.Equal(value1, config["Key1"], StringComparer.InvariantCultureIgnoreCase);
+ Assert.Equal(value12, config["Section1:Key2"], StringComparer.InvariantCultureIgnoreCase);
+ Assert.Equal(value123, config["Section1:Section2:Key3"], StringComparer.InvariantCultureIgnoreCase);
+ Assert.Equal(arrayvalue0, config["Section1:Section2:Key3a:0"], StringComparer.InvariantCultureIgnoreCase);
+ Assert.Equal(arrayvalue1, config["Section1:Section2:Key3a:1"], StringComparer.InvariantCultureIgnoreCase);
+ Assert.Equal(arrayvalue2, config["Section1:Section2:Key3a:2"], StringComparer.InvariantCultureIgnoreCase);
+ Assert.Equal(value344, config["Section3:Section4:Key4"], StringComparer.InvariantCultureIgnoreCase);
+
+ var section1 = config.GetSection("Section1");
+ Assert.Equal(value12, section1["Key2"], StringComparer.InvariantCultureIgnoreCase);
+ Assert.Equal(value123, section1["Section2:Key3"], StringComparer.InvariantCultureIgnoreCase);
+ Assert.Equal(arrayvalue0, section1["Section2:Key3a:0"], StringComparer.InvariantCultureIgnoreCase);
+ Assert.Equal(arrayvalue1, section1["Section2:Key3a:1"], StringComparer.InvariantCultureIgnoreCase);
+ Assert.Equal(arrayvalue2, section1["Section2:Key3a:2"], StringComparer.InvariantCultureIgnoreCase);
+ Assert.Equal("Section1", section1.Path, StringComparer.InvariantCultureIgnoreCase);
+ Assert.Null(section1.Value);
+
+ var section2 = config.GetSection("Section1:Section2");
+ Assert.Equal(value123, section2["Key3"], StringComparer.InvariantCultureIgnoreCase);
+ Assert.Equal(arrayvalue0, section2["Key3a:0"], StringComparer.InvariantCultureIgnoreCase);
+ Assert.Equal(arrayvalue1, section2["Key3a:1"], StringComparer.InvariantCultureIgnoreCase);
+ Assert.Equal(arrayvalue2, section2["Key3a:2"], StringComparer.InvariantCultureIgnoreCase);
+ Assert.Equal("Section1:Section2", section2.Path, StringComparer.InvariantCultureIgnoreCase);
+ Assert.Null(section2.Value);
+
+ section2 = section1.GetSection("Section2");
+ Assert.Equal(value123, section2["Key3"], StringComparer.InvariantCultureIgnoreCase);
+ Assert.Equal(arrayvalue0, section2["Key3a:0"], StringComparer.InvariantCultureIgnoreCase);
+ Assert.Equal(arrayvalue1, section2["Key3a:1"], StringComparer.InvariantCultureIgnoreCase);
+ Assert.Equal(arrayvalue2, section2["Key3a:2"], StringComparer.InvariantCultureIgnoreCase);
+ Assert.Equal("Section1:Section2", section2.Path, StringComparer.InvariantCultureIgnoreCase);
+ Assert.Null(section2.Value);
+
+ var section3a = section2.GetSection("Key3a");
+ Assert.Equal(arrayvalue0, section3a["0"], StringComparer.InvariantCultureIgnoreCase);
+ Assert.Equal(arrayvalue1, section3a["1"], StringComparer.InvariantCultureIgnoreCase);
+ Assert.Equal(arrayvalue2, section3a["2"], StringComparer.InvariantCultureIgnoreCase);
+ Assert.Equal("Section1:Section2:Key3a", section3a.Path, StringComparer.InvariantCultureIgnoreCase);
+ Assert.Null(section3a.Value);
+
+ var section3 = config.GetSection("Section3");
+ Assert.Equal("Section3", section3.Path, StringComparer.InvariantCultureIgnoreCase);
+ Assert.Null(section3.Value);
+
+ var section4 = config.GetSection("Section3:Section4");
+ Assert.Equal(value344, section4["Key4"], StringComparer.InvariantCultureIgnoreCase);
+ Assert.Equal("Section3:Section4", section4.Path, StringComparer.InvariantCultureIgnoreCase);
+ Assert.Null(section4.Value);
+
+ section4 = config.GetSection("Section3").GetSection("Section4");
+ Assert.Equal(value344, section4["Key4"], StringComparer.InvariantCultureIgnoreCase);
+ Assert.Equal("Section3:Section4", section4.Path, StringComparer.InvariantCultureIgnoreCase);
+ Assert.Null(section4.Value);
+
+ var sections = config.GetChildren().ToList();
+
+ Assert.Equal(3, sections.Count);
+
+ Assert.Equal("Key1", sections[0].Key, StringComparer.InvariantCultureIgnoreCase);
+ Assert.Equal("Key1", sections[0].Path, StringComparer.InvariantCultureIgnoreCase);
+ Assert.Equal(value1, sections[0].Value, StringComparer.InvariantCultureIgnoreCase);
+
+ Assert.Equal("Section1", sections[1].Key, StringComparer.InvariantCultureIgnoreCase);
+ Assert.Equal("Section1", sections[1].Path, StringComparer.InvariantCultureIgnoreCase);
+ Assert.Null(sections[1].Value);
+
+ Assert.Equal("Section3", sections[2].Key, StringComparer.InvariantCultureIgnoreCase);
+ Assert.Equal("Section3", sections[2].Path, StringComparer.InvariantCultureIgnoreCase);
+ Assert.Null(sections[2].Value);
+
+ sections = section1.GetChildren().ToList();
+
+ Assert.Equal(2, sections.Count);
+
+ Assert.Equal("Key2", sections[0].Key, StringComparer.InvariantCultureIgnoreCase);
+ Assert.Equal("Section1:Key2", sections[0].Path, StringComparer.InvariantCultureIgnoreCase);
+ Assert.Equal(value12, sections[0].Value, StringComparer.InvariantCultureIgnoreCase);
+
+ Assert.Equal("Section2", sections[1].Key, StringComparer.InvariantCultureIgnoreCase);
+ Assert.Equal("Section1:Section2", sections[1].Path, StringComparer.InvariantCultureIgnoreCase);
+ Assert.Null(sections[1].Value);
+
+ sections = section2.GetChildren().ToList();
+
+ Assert.Equal(2, sections.Count);
+
+ Assert.Equal("Key3", sections[0].Key, StringComparer.InvariantCultureIgnoreCase);
+ Assert.Equal("Section1:Section2:Key3", sections[0].Path, StringComparer.InvariantCultureIgnoreCase);
+ Assert.Equal(value123, sections[0].Value, StringComparer.InvariantCultureIgnoreCase);
+
+ Assert.Equal("Key3a", sections[1].Key, StringComparer.InvariantCultureIgnoreCase);
+ Assert.Equal("Section1:Section2:Key3a", sections[1].Path, StringComparer.InvariantCultureIgnoreCase);
+ Assert.Null(sections[1].Value);
+
+ sections = section3a.GetChildren().ToList();
+
+ Assert.Equal(3, sections.Count);
+
+ Assert.Equal("0", sections[0].Key, StringComparer.InvariantCultureIgnoreCase);
+ Assert.Equal("Section1:Section2:Key3a:0", sections[0].Path, StringComparer.InvariantCultureIgnoreCase);
+ Assert.Equal(arrayvalue0, sections[0].Value, StringComparer.InvariantCultureIgnoreCase);
+
+ Assert.Equal("1", sections[1].Key, StringComparer.InvariantCultureIgnoreCase);
+ Assert.Equal("Section1:Section2:Key3a:1", sections[1].Path, StringComparer.InvariantCultureIgnoreCase);
+ Assert.Equal(arrayvalue1, sections[1].Value, StringComparer.InvariantCultureIgnoreCase);
+
+ Assert.Equal("2", sections[2].Key, StringComparer.InvariantCultureIgnoreCase);
+ Assert.Equal("Section1:Section2:Key3a:2", sections[2].Path, StringComparer.InvariantCultureIgnoreCase);
+ Assert.Equal(arrayvalue2, sections[2].Value, StringComparer.InvariantCultureIgnoreCase);
+
+ sections = section3.GetChildren().ToList();
+
+ Assert.Single(sections);
+
+ Assert.Equal("Section4", sections[0].Key, StringComparer.InvariantCultureIgnoreCase);
+ Assert.Equal("Section3:Section4", sections[0].Path, StringComparer.InvariantCultureIgnoreCase);
+ Assert.Null(sections[0].Value);
+
+ sections = section4.GetChildren().ToList();
+
+ Assert.Single(sections);
+
+ Assert.Equal("Key4", sections[0].Key, StringComparer.InvariantCultureIgnoreCase);
+ Assert.Equal("Section3:Section4:Key4", sections[0].Path, StringComparer.InvariantCultureIgnoreCase);
+ Assert.Equal(value344, sections[0].Value, StringComparer.InvariantCultureIgnoreCase);
+ }
+
+ protected abstract (IConfigurationProvider Provider, Action Initializer) LoadThroughProvider(TestSection testConfig);
+
+ protected virtual IConfigurationRoot BuildConfigRoot(
+ params (IConfigurationProvider Provider, Action Initializer)[] providers)
+ {
+ var root = new ConfigurationRoot(providers.Select(e => e.Provider).ToList());
+
+ foreach (var initializer in providers.Select(e => e.Initializer))
+ {
+ initializer();
+ }
+
+ return root;
+ }
+
+ protected static (IConfigurationProvider Provider, Action Initializer) LoadUsingMemoryProvider(TestSection testConfig)
+ {
+ var values = new List>();
+ SectionToValues(testConfig, "", values);
+
+ return (new MemoryConfigurationProvider(
+ new MemoryConfigurationSource
+ {
+ InitialData = values
+ }),
+ () => { });
+ }
+
+ protected static void SectionToValues(
+ TestSection section,
+ string sectionName,
+ IList> values)
+ {
+ foreach (var tuple in section.Values.SelectMany(e => e.Value.Expand(e.Key)))
+ {
+ values.Add(new KeyValuePair(sectionName + tuple.Key, tuple.Value));
+ }
+
+ foreach (var tuple in section.Sections)
+ {
+ SectionToValues(
+ tuple.Section,
+ sectionName + tuple.Key + ":",
+ values);
+ }
+ }
+
+ protected class TestKeyValue
+ {
+ public object Value { get; }
+
+ public TestKeyValue(string value)
+ {
+ Value = value;
+ }
+
+ public TestKeyValue(string[] values)
+ {
+ Value = values;
+ }
+
+ public static implicit operator TestKeyValue(string value) => new TestKeyValue(value);
+ public static implicit operator TestKeyValue(string[] values) => new TestKeyValue(values);
+
+ public string[] AsArray => Value as string[];
+
+ public string AsString => Value as string;
+
+ public IEnumerable<(string Key, string Value)> Expand(string key)
+ {
+ if (AsArray == null)
+ {
+ yield return (key, AsString);
+ }
+ else
+ {
+ for (var i = 0; i < AsArray.Length; i++)
+ {
+ yield return ($"{key}:{i}", AsArray[i]);
+ }
+ }
+ }
+ }
+
+ protected class TestSection
+ {
+ public IEnumerable<(string Key, TestKeyValue Value)> Values { get; set; }
+ = Enumerable.Empty<(string, TestKeyValue)>();
+
+ public IEnumerable<(string Key, TestSection Section)> Sections { get; set; }
+ = Enumerable.Empty<(string, TestSection)>();
+
+ public static TestSection TestConfig { get; }
+ = new TestSection
+ {
+ Values = new[] { ("Key1", (TestKeyValue)"Value1") },
+ Sections = new[]
+ {
+ ("Section1", new TestSection
+ {
+ Values = new[] {("Key2", (TestKeyValue)"Value12")},
+ Sections = new[]
+ {
+ ("Section2", new TestSection
+ {
+ Values = new[]
+ {
+ ("Key3", (TestKeyValue)"Value123"),
+ ("Key3a", (TestKeyValue)new[] {"ArrayValue0", "ArrayValue1", "ArrayValue2"})
+ },
+ })
+ }
+ }),
+ ("Section3", new TestSection
+ {
+ Sections = new[]
+ {
+ ("Section4", new TestSection
+ {
+ Values = new[] {("Key4", (TestKeyValue)"Value344")}
+ })
+ }
+ })
+ }
+ };
+
+ public static TestSection NoValuesTestConfig { get; }
+ = new TestSection
+ {
+ Values = new[] { ("Key1", (TestKeyValue)"------") },
+ Sections = new[]
+ {
+ ("Section1", new TestSection
+ {
+ Values = new[] {("Key2", (TestKeyValue)"-------")},
+ Sections = new[]
+ {
+ ("Section2", new TestSection
+ {
+ Values = new[]
+ {
+ ("Key3", (TestKeyValue)"-----"),
+ ("Key3a", (TestKeyValue)new[] {"-----------", "-----------", "-----------"})
+ },
+ })
+ }
+ }),
+ ("Section3", new TestSection
+ {
+ Sections = new[]
+ {
+ ("Section4", new TestSection
+ {
+ Values = new[] {("Key4", (TestKeyValue)"--------")}
+ })
+ }
+ })
+ }
+ };
+
+ public static TestSection MissingSection2ValuesConfig { get; }
+ = new TestSection
+ {
+ Values = new[] { ("Key1", (TestKeyValue)"Value1") },
+ Sections = new[]
+ {
+ ("Section1", new TestSection
+ {
+ Values = new[] {("Key2", (TestKeyValue)"Value12")},
+ Sections = new[]
+ {
+ ("Section2", new TestSection
+ {
+ Values = new[]
+ {
+ ("Key3a", (TestKeyValue)new[] {"ArrayValue0"})
+ },
+ })
+ }
+ }),
+ ("Section3", new TestSection
+ {
+ Sections = new[]
+ {
+ ("Section4", new TestSection
+ {
+ Values = new[] {("Key4", (TestKeyValue)"Value344")}
+ })
+ }
+ })
+ }
+ };
+
+
+ public static TestSection MissingSection4Config { get; }
+ = new TestSection
+ {
+ Values = new[] { ("Key1", (TestKeyValue)"Value1") },
+ Sections = new[]
+ {
+ ("Section1", new TestSection
+ {
+ Values = new[] {("Key2", (TestKeyValue)"Value12")},
+ Sections = new[]
+ {
+ ("Section2", new TestSection
+ {
+ Values = new[]
+ {
+ ("Key3", (TestKeyValue)"Value123"),
+ ("Key3a", (TestKeyValue)new[] {"ArrayValue0", "ArrayValue1", "ArrayValue2"})
+ },
+ })
+ }
+ }),
+ ("Section3", new TestSection())
+ }
+ };
+
+ public static TestSection DifferentCasedTestConfig { get; }
+ = new TestSection
+ {
+ Values = new[] { ("KeY1", (TestKeyValue)"Value1") },
+ Sections = new[]
+ {
+ ("SectioN1", new TestSection
+ {
+ Values = new[] {("KeY2", (TestKeyValue)"Value12")},
+ Sections = new[]
+ {
+ ("SectioN2", new TestSection
+ {
+ Values = new[]
+ {
+ ("KeY3", (TestKeyValue)"Value123"),
+ ("KeY3a", (TestKeyValue)new[] {"ArrayValue0", "ArrayValue1", "ArrayValue2"})
+ },
+ })
+ }
+ }),
+ ("SectioN3", new TestSection
+ {
+ Sections = new[]
+ {
+ ("SectioN4", new TestSection
+ {
+ Values = new[] {("KeY4", (TestKeyValue)"Value344")}
+ })
+ }
+ })
+ }
+ };
+
+ public static TestSection DuplicatesTestConfig { get; }
+ = new TestSection
+ {
+ Values = new[]
+ {
+ ("Key1", (TestKeyValue)"Value1"),
+ ("Key1", (TestKeyValue)"Value1")
+ },
+ Sections = new[]
+ {
+ ("Section1", new TestSection
+ {
+ Values = new[] {("Key2", (TestKeyValue)"Value12")},
+ Sections = new[]
+ {
+ ("Section2", new TestSection
+ {
+ Values = new[]
+ {
+ ("Key3", (TestKeyValue)"Value123"),
+ ("Key3a", (TestKeyValue)new[] {"ArrayValue0", "ArrayValue1", "ArrayValue2"})
+ },
+ }),
+ ("Section2", new TestSection
+ {
+ Values = new[]
+ {
+ ("Key3", (TestKeyValue)"Value123"),
+ ("Key3a", (TestKeyValue)new[] {"ArrayValue0", "ArrayValue1", "ArrayValue2"})
+ },
+ })
+
+ }
+ }),
+ ("Section3", new TestSection
+ {
+ Sections = new[]
+ {
+ ("Section4", new TestSection
+ {
+ Values = new[] {("Key4", (TestKeyValue)"Value344")}
+ })
+ }
+ })
+ }
+ };
+
+ public static TestSection DuplicatesDifferentCaseTestConfig { get; }
+ = new TestSection
+ {
+ Values = new[]
+ {
+ ("Key1", (TestKeyValue)"Value1"),
+ ("KeY1", (TestKeyValue)"Value1")
+ },
+ Sections = new[]
+ {
+ ("Section1", new TestSection
+ {
+ Values = new[] {("Key2", (TestKeyValue)"Value12")},
+ Sections = new[]
+ {
+ ("Section2", new TestSection
+ {
+ Values = new[]
+ {
+ ("Key3", (TestKeyValue)"Value123"),
+ ("Key3a", (TestKeyValue)new[] {"ArrayValue0", "ArrayValue1", "ArrayValue2"})
+ },
+ }),
+ ("SectioN2", new TestSection
+ {
+ Values = new[]
+ {
+ ("KeY3", (TestKeyValue)"Value123"),
+ ("KeY3a", (TestKeyValue)new[] {"ArrayValue0", "ArrayValue1", "ArrayValue2"})
+ },
+ })
+
+ }
+ }),
+ ("Section3", new TestSection
+ {
+ Sections = new[]
+ {
+ ("Section4", new TestSection
+ {
+ Values = new[] {("Key4", (TestKeyValue)"Value344")}
+ })
+ }
+ })
+ }
+ };
+
+ public static TestSection NullsTestConfig { get; }
+ = new TestSection
+ {
+ Values = new[] { ("Key1", new TestKeyValue((string)null)) },
+ Sections = new[]
+ {
+ ("Section1", new TestSection
+ {
+ Values = new[] {("Key2", new TestKeyValue((string)null))},
+ Sections = new[]
+ {
+ ("Section2", new TestSection
+ {
+ Values = new[]
+ {
+ ("Key3", new TestKeyValue((string)null)),
+ ("Key3a", (TestKeyValue)new string[] {null, null, null})
+ },
+ })
+ }
+ }),
+ ("Section3", new TestSection
+ {
+ Sections = new[]
+ {
+ ("Section4", new TestSection
+ {
+ Values = new[] {("Key4", new TestKeyValue((string)null))}
+ })
+ }
+ })
+ }
+ };
+
+ public static TestSection ExtraValuesTestConfig { get; }
+ = new TestSection
+ {
+ Values = new[]
+ {
+ ("Key1", (TestKeyValue)"Value1"),
+ ("Key1r", (TestKeyValue)"Value1r")
+ },
+ Sections = new[]
+ {
+ ("Section1", new TestSection
+ {
+ Values = new[]
+ {
+ ("Key2", (TestKeyValue)"Value12"),
+ ("Key2r", (TestKeyValue)"Value12r")
+ },
+ Sections = new[]
+ {
+ ("Section2", new TestSection
+ {
+ Values = new[]
+ {
+ ("Key3", (TestKeyValue)"Value123"),
+ ("Key3a", (TestKeyValue)new[] {"ArrayValue0", "ArrayValue1", "ArrayValue2", "ArrayValue2r"}),
+ ("Key3ar", (TestKeyValue)new[] {"ArrayValue0r"})
+ },
+ })
+ }
+ }),
+ ("Section3", new TestSection
+ {
+ Sections = new[]
+ {
+ ("Section4", new TestSection
+ {
+ Values = new[] {("Key4", (TestKeyValue)"Value344")}
+ })
+ }
+ }),
+ ("Section5r", new TestSection
+ {
+ Sections = new[]
+ {
+ ("Section6r", new TestSection
+ {
+ Values = new[] {("Key5r", (TestKeyValue)"Value565r")}
+ })
+ }
+ })
+ }
+ };
+ }
+ }
+}
diff --git a/src/Configuration.KeyPerFile/test/KeyPerFileTests.cs b/src/Configuration.KeyPerFile/test/KeyPerFileTests.cs
index 499c25106c..838e62222d 100644
--- a/src/Configuration.KeyPerFile/test/KeyPerFileTests.cs
+++ b/src/Configuration.KeyPerFile/test/KeyPerFileTests.cs
@@ -1,8 +1,10 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
-using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
@@ -195,7 +197,15 @@ namespace Microsoft.Extensions.Configuration.KeyPerFile.Test
using (var cts = new CancellationTokenSource(TimeSpan.FromMilliseconds(250)))
{
- _ = Task.Run(() => { while (!cts.IsCancellationRequested) config.Reload(); });
+ void ReloadLoop()
+ {
+ while (!cts.IsCancellationRequested)
+ {
+ config.Reload();
+ }
+ }
+
+ _ = Task.Run(ReloadLoop);
while (!cts.IsCancellationRequested)
{
@@ -223,20 +233,11 @@ namespace Microsoft.Extensions.Configuration.KeyPerFile.Test
_contents = new TestDirectoryContents(files);
}
- public IDirectoryContents GetDirectoryContents(string subpath)
- {
- return _contents;
- }
+ public IDirectoryContents GetDirectoryContents(string subpath) => _contents;
- public IFileInfo GetFileInfo(string subpath)
- {
- throw new NotImplementedException();
- }
+ public IFileInfo GetFileInfo(string subpath) => new TestFile("TestDirectory");
- public IChangeToken Watch(string filter)
- {
- throw new NotImplementedException();
- }
+ public IChangeToken Watch(string filter) => throw new NotImplementedException();
}
class TestDirectoryContents : IDirectoryContents
@@ -248,75 +249,33 @@ namespace Microsoft.Extensions.Configuration.KeyPerFile.Test
_list = new List(files);
}
- public bool Exists
- {
- get
- {
- return true;
- }
- }
+ public bool Exists => true;
- public IEnumerator GetEnumerator()
- {
- return _list.GetEnumerator();
- }
+ public IEnumerator GetEnumerator() => _list.GetEnumerator();
- IEnumerator IEnumerable.GetEnumerator()
- {
- return GetEnumerator();
- }
+ IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
//TODO: Probably need a directory and file type.
class TestFile : IFileInfo
{
- private string _name;
- private string _contents;
+ private readonly string _name;
+ private readonly string _contents;
- public bool Exists
- {
- get
- {
- return true;
- }
- }
+ public bool Exists => true;
public bool IsDirectory
{
get;
}
- public DateTimeOffset LastModified
- {
- get
- {
- throw new NotImplementedException();
- }
- }
+ public DateTimeOffset LastModified => throw new NotImplementedException();
- public long Length
- {
- get
- {
- throw new NotImplementedException();
- }
- }
+ public long Length => throw new NotImplementedException();
- public string Name
- {
- get
- {
- return _name;
- }
- }
+ public string Name => _name;
- public string PhysicalPath
- {
- get
- {
- throw new NotImplementedException();
- }
- }
+ public string PhysicalPath => "Root/" + Name;
public TestFile(string name)
{
@@ -337,7 +296,9 @@ namespace Microsoft.Extensions.Configuration.KeyPerFile.Test
throw new InvalidOperationException("Cannot create stream from directory");
}
- return new MemoryStream(Encoding.UTF8.GetBytes(_contents));
+ return _contents == null
+ ? new MemoryStream()
+ : new MemoryStream(Encoding.UTF8.GetBytes(_contents));
}
}
}
diff --git a/src/Configuration.KeyPerFile/test/Microsoft.Extensions.Configuration.KeyPerFile.Tests.csproj b/src/Configuration.KeyPerFile/test/Microsoft.Extensions.Configuration.KeyPerFile.Tests.csproj
index 154fd5bb62..aee7e7a7bf 100644
--- a/src/Configuration.KeyPerFile/test/Microsoft.Extensions.Configuration.KeyPerFile.Tests.csproj
+++ b/src/Configuration.KeyPerFile/test/Microsoft.Extensions.Configuration.KeyPerFile.Tests.csproj
@@ -1,11 +1,14 @@
- netcoreapp2.2;net461
+ netcoreapp3.0;net472
-
+
+
+
+
diff --git a/src/FileProviders/Directory.Build.props b/src/FileProviders/Directory.Build.props
index bf4410dcb7..709c47ddbd 100644
--- a/src/FileProviders/Directory.Build.props
+++ b/src/FileProviders/Directory.Build.props
@@ -2,7 +2,7 @@
- true
+ true
files;filesystem
diff --git a/src/FileProviders/Embedded/Directory.Build.props b/src/FileProviders/Embedded/Directory.Build.props
deleted file mode 100644
index f25c1d90ce..0000000000
--- a/src/FileProviders/Embedded/Directory.Build.props
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
- true
-
-
diff --git a/src/FileProviders/Embedded/ref/Microsoft.Extensions.FileProviders.Embedded.csproj b/src/FileProviders/Embedded/ref/Microsoft.Extensions.FileProviders.Embedded.csproj
new file mode 100644
index 0000000000..b8f2f33387
--- /dev/null
+++ b/src/FileProviders/Embedded/ref/Microsoft.Extensions.FileProviders.Embedded.csproj
@@ -0,0 +1,10 @@
+
+
+
+ netstandard2.0
+
+
+
+
+
+
diff --git a/src/FileProviders/Embedded/ref/Microsoft.Extensions.FileProviders.Embedded.netstandard2.0.cs b/src/FileProviders/Embedded/ref/Microsoft.Extensions.FileProviders.Embedded.netstandard2.0.cs
new file mode 100644
index 0000000000..1596f191fd
--- /dev/null
+++ b/src/FileProviders/Embedded/ref/Microsoft.Extensions.FileProviders.Embedded.netstandard2.0.cs
@@ -0,0 +1,39 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Microsoft.Extensions.FileProviders
+{
+ public partial class EmbeddedFileProvider : Microsoft.Extensions.FileProviders.IFileProvider
+ {
+ public EmbeddedFileProvider(System.Reflection.Assembly assembly) { }
+ public EmbeddedFileProvider(System.Reflection.Assembly assembly, string baseNamespace) { }
+ public Microsoft.Extensions.FileProviders.IDirectoryContents GetDirectoryContents(string subpath) { throw null; }
+ public Microsoft.Extensions.FileProviders.IFileInfo GetFileInfo(string subpath) { throw null; }
+ public Microsoft.Extensions.Primitives.IChangeToken Watch(string pattern) { throw null; }
+ }
+ public partial class ManifestEmbeddedFileProvider : Microsoft.Extensions.FileProviders.IFileProvider
+ {
+ public ManifestEmbeddedFileProvider(System.Reflection.Assembly assembly) { }
+ public ManifestEmbeddedFileProvider(System.Reflection.Assembly assembly, string root) { }
+ public ManifestEmbeddedFileProvider(System.Reflection.Assembly assembly, string root, System.DateTimeOffset lastModified) { }
+ public ManifestEmbeddedFileProvider(System.Reflection.Assembly assembly, string root, string manifestName, System.DateTimeOffset lastModified) { }
+ public System.Reflection.Assembly Assembly { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
+ public Microsoft.Extensions.FileProviders.IDirectoryContents GetDirectoryContents(string subpath) { throw null; }
+ public Microsoft.Extensions.FileProviders.IFileInfo GetFileInfo(string subpath) { throw null; }
+ public Microsoft.Extensions.Primitives.IChangeToken Watch(string filter) { throw null; }
+ }
+}
+namespace Microsoft.Extensions.FileProviders.Embedded
+{
+ public partial class EmbeddedResourceFileInfo : Microsoft.Extensions.FileProviders.IFileInfo
+ {
+ public EmbeddedResourceFileInfo(System.Reflection.Assembly assembly, string resourcePath, string name, System.DateTimeOffset lastModified) { }
+ public bool Exists { get { throw null; } }
+ public bool IsDirectory { get { throw null; } }
+ public System.DateTimeOffset LastModified { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
+ public long Length { get { throw null; } }
+ public string Name { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
+ public string PhysicalPath { get { throw null; } }
+ public System.IO.Stream CreateReadStream() { throw null; }
+ }
+}
diff --git a/src/FileProviders/Embedded/src/Microsoft.Extensions.FileProviders.Embedded.csproj b/src/FileProviders/Embedded/src/Microsoft.Extensions.FileProviders.Embedded.csproj
index 191330625a..792b9ff5b3 100644
--- a/src/FileProviders/Embedded/src/Microsoft.Extensions.FileProviders.Embedded.csproj
+++ b/src/FileProviders/Embedded/src/Microsoft.Extensions.FileProviders.Embedded.csproj
@@ -5,8 +5,13 @@
File provider for files in embedded resources for Microsoft.Extensions.FileProviders.
netstandard2.0
$(MSBuildProjectName).nuspec
+ true
+
+
+
+
@@ -18,7 +23,6 @@
-
id=$(PackageId);
@@ -40,12 +44,9 @@
OutputDocumentation=@(DocumentationProjectOutputGroupOutput);
- TaskAssemblyNetStandard=..\..\Manifest.MSBuildTask\src\bin\$(Configuration)\netstandard1.5\$(AssemblyName).Manifest.Task.dll;
- TaskSymbolNetStandard=..\..\Manifest.MSBuildTask\src\bin\$(Configuration)\netstandard1.5\$(AssemblyName).Manifest.Task.pdb;
- TaskAssemblyNet461=..\..\Manifest.MSBuildTask\src\bin\$(Configuration)\net461\$(AssemblyName).Manifest.Task.dll;
- TaskSymbolNet461=..\..\Manifest.MSBuildTask\src\bin\$(Configuration)\net461\$(AssemblyName).Manifest.Task.pdb;
+ TaskAssemblyNetStandard=$(ArtifactsDir)bin\$(AssemblyName).Manifest.Task\$(Configuration)\netstandard2.0\$(AssemblyName).Manifest.Task.dll;
+ TaskSymbolNetStandard=$(ArtifactsDir)bin\$(AssemblyName).Manifest.Task\$(Configuration)\netstandard2.0\$(AssemblyName).Manifest.Task.pdb;
-
diff --git a/src/FileProviders/Embedded/src/Microsoft.Extensions.FileProviders.Embedded.nuspec b/src/FileProviders/Embedded/src/Microsoft.Extensions.FileProviders.Embedded.nuspec
index 0cc5ed823a..ff6d385add 100644
--- a/src/FileProviders/Embedded/src/Microsoft.Extensions.FileProviders.Embedded.nuspec
+++ b/src/FileProviders/Embedded/src/Microsoft.Extensions.FileProviders.Embedded.nuspec
@@ -25,9 +25,7 @@
-
-
-
-
+
+
-
\ No newline at end of file
+
diff --git a/src/FileProviders/Embedded/src/Properties/AssemblyInfo.cs b/src/FileProviders/Embedded/src/Properties/AssemblyInfo.cs
deleted file mode 100644
index 610a7fa706..0000000000
--- a/src/FileProviders/Embedded/src/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,4 +0,0 @@
-
-using System.Runtime.CompilerServices;
-
-[assembly: InternalsVisibleTo("Microsoft.Extensions.FileProviders.Embedded.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
\ No newline at end of file
diff --git a/src/FileProviders/Embedded/src/baseline.netcore.json b/src/FileProviders/Embedded/src/baseline.netcore.json
deleted file mode 100644
index 821969ea0b..0000000000
--- a/src/FileProviders/Embedded/src/baseline.netcore.json
+++ /dev/null
@@ -1,343 +0,0 @@
-{
- "AssemblyIdentity": "Microsoft.Extensions.FileProviders.Embedded, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60",
- "Types": [
- {
- "Name": "Microsoft.Extensions.FileProviders.EmbeddedFileProvider",
- "Visibility": "Public",
- "Kind": "Class",
- "ImplementedInterfaces": [
- "Microsoft.Extensions.FileProviders.IFileProvider"
- ],
- "Members": [
- {
- "Kind": "Method",
- "Name": "GetFileInfo",
- "Parameters": [
- {
- "Name": "subpath",
- "Type": "System.String"
- }
- ],
- "ReturnType": "Microsoft.Extensions.FileProviders.IFileInfo",
- "Sealed": true,
- "Virtual": true,
- "ImplementedInterface": "Microsoft.Extensions.FileProviders.IFileProvider",
- "Visibility": "Public",
- "GenericParameter": []
- },
- {
- "Kind": "Method",
- "Name": "GetDirectoryContents",
- "Parameters": [
- {
- "Name": "subpath",
- "Type": "System.String"
- }
- ],
- "ReturnType": "Microsoft.Extensions.FileProviders.IDirectoryContents",
- "Sealed": true,
- "Virtual": true,
- "ImplementedInterface": "Microsoft.Extensions.FileProviders.IFileProvider",
- "Visibility": "Public",
- "GenericParameter": []
- },
- {
- "Kind": "Method",
- "Name": "Watch",
- "Parameters": [
- {
- "Name": "pattern",
- "Type": "System.String"
- }
- ],
- "ReturnType": "Microsoft.Extensions.Primitives.IChangeToken",
- "Sealed": true,
- "Virtual": true,
- "ImplementedInterface": "Microsoft.Extensions.FileProviders.IFileProvider",
- "Visibility": "Public",
- "GenericParameter": []
- },
- {
- "Kind": "Constructor",
- "Name": ".ctor",
- "Parameters": [
- {
- "Name": "assembly",
- "Type": "System.Reflection.Assembly"
- }
- ],
- "Visibility": "Public",
- "GenericParameter": []
- },
- {
- "Kind": "Constructor",
- "Name": ".ctor",
- "Parameters": [
- {
- "Name": "assembly",
- "Type": "System.Reflection.Assembly"
- },
- {
- "Name": "baseNamespace",
- "Type": "System.String"
- }
- ],
- "Visibility": "Public",
- "GenericParameter": []
- }
- ],
- "GenericParameters": []
- },
- {
- "Name": "Microsoft.Extensions.FileProviders.ManifestEmbeddedFileProvider",
- "Visibility": "Public",
- "Kind": "Class",
- "ImplementedInterfaces": [
- "Microsoft.Extensions.FileProviders.IFileProvider"
- ],
- "Members": [
- {
- "Kind": "Method",
- "Name": "get_Assembly",
- "Parameters": [],
- "ReturnType": "System.Reflection.Assembly",
- "Visibility": "Public",
- "GenericParameter": []
- },
- {
- "Kind": "Method",
- "Name": "GetDirectoryContents",
- "Parameters": [
- {
- "Name": "subpath",
- "Type": "System.String"
- }
- ],
- "ReturnType": "Microsoft.Extensions.FileProviders.IDirectoryContents",
- "Sealed": true,
- "Virtual": true,
- "ImplementedInterface": "Microsoft.Extensions.FileProviders.IFileProvider",
- "Visibility": "Public",
- "GenericParameter": []
- },
- {
- "Kind": "Method",
- "Name": "GetFileInfo",
- "Parameters": [
- {
- "Name": "subpath",
- "Type": "System.String"
- }
- ],
- "ReturnType": "Microsoft.Extensions.FileProviders.IFileInfo",
- "Sealed": true,
- "Virtual": true,
- "ImplementedInterface": "Microsoft.Extensions.FileProviders.IFileProvider",
- "Visibility": "Public",
- "GenericParameter": []
- },
- {
- "Kind": "Method",
- "Name": "Watch",
- "Parameters": [
- {
- "Name": "filter",
- "Type": "System.String"
- }
- ],
- "ReturnType": "Microsoft.Extensions.Primitives.IChangeToken",
- "Sealed": true,
- "Virtual": true,
- "ImplementedInterface": "Microsoft.Extensions.FileProviders.IFileProvider",
- "Visibility": "Public",
- "GenericParameter": []
- },
- {
- "Kind": "Constructor",
- "Name": ".ctor",
- "Parameters": [
- {
- "Name": "assembly",
- "Type": "System.Reflection.Assembly"
- }
- ],
- "Visibility": "Public",
- "GenericParameter": []
- },
- {
- "Kind": "Constructor",
- "Name": ".ctor",
- "Parameters": [
- {
- "Name": "assembly",
- "Type": "System.Reflection.Assembly"
- },
- {
- "Name": "root",
- "Type": "System.String"
- }
- ],
- "Visibility": "Public",
- "GenericParameter": []
- },
- {
- "Kind": "Constructor",
- "Name": ".ctor",
- "Parameters": [
- {
- "Name": "assembly",
- "Type": "System.Reflection.Assembly"
- },
- {
- "Name": "root",
- "Type": "System.String"
- },
- {
- "Name": "lastModified",
- "Type": "System.DateTimeOffset"
- }
- ],
- "Visibility": "Public",
- "GenericParameter": []
- },
- {
- "Kind": "Constructor",
- "Name": ".ctor",
- "Parameters": [
- {
- "Name": "assembly",
- "Type": "System.Reflection.Assembly"
- },
- {
- "Name": "root",
- "Type": "System.String"
- },
- {
- "Name": "manifestName",
- "Type": "System.String"
- },
- {
- "Name": "lastModified",
- "Type": "System.DateTimeOffset"
- }
- ],
- "Visibility": "Public",
- "GenericParameter": []
- }
- ],
- "GenericParameters": []
- },
- {
- "Name": "Microsoft.Extensions.FileProviders.Embedded.EmbeddedResourceFileInfo",
- "Visibility": "Public",
- "Kind": "Class",
- "ImplementedInterfaces": [
- "Microsoft.Extensions.FileProviders.IFileInfo"
- ],
- "Members": [
- {
- "Kind": "Method",
- "Name": "get_Exists",
- "Parameters": [],
- "ReturnType": "System.Boolean",
- "Sealed": true,
- "Virtual": true,
- "ImplementedInterface": "Microsoft.Extensions.FileProviders.IFileInfo",
- "Visibility": "Public",
- "GenericParameter": []
- },
- {
- "Kind": "Method",
- "Name": "get_Length",
- "Parameters": [],
- "ReturnType": "System.Int64",
- "Sealed": true,
- "Virtual": true,
- "ImplementedInterface": "Microsoft.Extensions.FileProviders.IFileInfo",
- "Visibility": "Public",
- "GenericParameter": []
- },
- {
- "Kind": "Method",
- "Name": "get_PhysicalPath",
- "Parameters": [],
- "ReturnType": "System.String",
- "Sealed": true,
- "Virtual": true,
- "ImplementedInterface": "Microsoft.Extensions.FileProviders.IFileInfo",
- "Visibility": "Public",
- "GenericParameter": []
- },
- {
- "Kind": "Method",
- "Name": "get_Name",
- "Parameters": [],
- "ReturnType": "System.String",
- "Sealed": true,
- "Virtual": true,
- "ImplementedInterface": "Microsoft.Extensions.FileProviders.IFileInfo",
- "Visibility": "Public",
- "GenericParameter": []
- },
- {
- "Kind": "Method",
- "Name": "get_LastModified",
- "Parameters": [],
- "ReturnType": "System.DateTimeOffset",
- "Sealed": true,
- "Virtual": true,
- "ImplementedInterface": "Microsoft.Extensions.FileProviders.IFileInfo",
- "Visibility": "Public",
- "GenericParameter": []
- },
- {
- "Kind": "Method",
- "Name": "get_IsDirectory",
- "Parameters": [],
- "ReturnType": "System.Boolean",
- "Sealed": true,
- "Virtual": true,
- "ImplementedInterface": "Microsoft.Extensions.FileProviders.IFileInfo",
- "Visibility": "Public",
- "GenericParameter": []
- },
- {
- "Kind": "Method",
- "Name": "CreateReadStream",
- "Parameters": [],
- "ReturnType": "System.IO.Stream",
- "Sealed": true,
- "Virtual": true,
- "ImplementedInterface": "Microsoft.Extensions.FileProviders.IFileInfo",
- "Visibility": "Public",
- "GenericParameter": []
- },
- {
- "Kind": "Constructor",
- "Name": ".ctor",
- "Parameters": [
- {
- "Name": "assembly",
- "Type": "System.Reflection.Assembly"
- },
- {
- "Name": "resourcePath",
- "Type": "System.String"
- },
- {
- "Name": "name",
- "Type": "System.String"
- },
- {
- "Name": "lastModified",
- "Type": "System.DateTimeOffset"
- }
- ],
- "Visibility": "Public",
- "GenericParameter": []
- }
- ],
- "GenericParameters": []
- }
- ]
-}
\ No newline at end of file
diff --git a/src/FileProviders/Embedded/src/build/netstandard2.0/Microsoft.Extensions.FileProviders.Embedded.props b/src/FileProviders/Embedded/src/build/netstandard2.0/Microsoft.Extensions.FileProviders.Embedded.props
index e913e17321..aabbabc92f 100644
--- a/src/FileProviders/Embedded/src/build/netstandard2.0/Microsoft.Extensions.FileProviders.Embedded.props
+++ b/src/FileProviders/Embedded/src/build/netstandard2.0/Microsoft.Extensions.FileProviders.Embedded.props
@@ -5,9 +5,7 @@
- <_FileProviderTaskFolder Condition="'$(MSBuildRuntimeType)' == 'Core'">netstandard1.5
- <_FileProviderTaskFolder Condition="'$(MSBuildRuntimeType)' != 'Core'">net461
- <_FileProviderTaskAssembly>$(MSBuildThisFileDirectory)..\..\tasks\$(_FileProviderTaskFolder)\Microsoft.Extensions.FileProviders.Embedded.Manifest.Task.dll
+ <_FileProviderTaskAssembly>$(MSBuildThisFileDirectory)..\..\tasks\netstandard2.0\Microsoft.Extensions.FileProviders.Embedded.Manifest.Task.dll
- netcoreapp2.2;net461
+ netcoreapp3.0;net472
diff --git a/src/FileProviders/Manifest.MSBuildTask/src/Microsoft.Extensions.FileProviders.Embedded.Manifest.Task.csproj b/src/FileProviders/Manifest.MSBuildTask/src/Microsoft.Extensions.FileProviders.Embedded.Manifest.Task.csproj
index e6c42b46f1..cdc4ffdcb0 100644
--- a/src/FileProviders/Manifest.MSBuildTask/src/Microsoft.Extensions.FileProviders.Embedded.Manifest.Task.csproj
+++ b/src/FileProviders/Manifest.MSBuildTask/src/Microsoft.Extensions.FileProviders.Embedded.Manifest.Task.csproj
@@ -3,24 +3,16 @@
MSBuild task to generate a manifest that can be used by Microsoft.Extensions.FileProviders.Embedded to preserve
metadata of the files embedded in the assembly at compilation time.
- netstandard1.5;net461
+ netstandard2.0
false
- false
+ true
false
false
-
-
-
-
-
-
-
-
-
-
+
+
diff --git a/src/FileProviders/Manifest.MSBuildTask/test/Microsoft.Extensions.FileProviders.Embedded.Manifest.Task.Test.csproj b/src/FileProviders/Manifest.MSBuildTask/test/Microsoft.Extensions.FileProviders.Embedded.Manifest.Task.Tests.csproj
similarity index 51%
rename from src/FileProviders/Manifest.MSBuildTask/test/Microsoft.Extensions.FileProviders.Embedded.Manifest.Task.Test.csproj
rename to src/FileProviders/Manifest.MSBuildTask/test/Microsoft.Extensions.FileProviders.Embedded.Manifest.Task.Tests.csproj
index 8be54bf05d..ed68958fe8 100644
--- a/src/FileProviders/Manifest.MSBuildTask/test/Microsoft.Extensions.FileProviders.Embedded.Manifest.Task.Test.csproj
+++ b/src/FileProviders/Manifest.MSBuildTask/test/Microsoft.Extensions.FileProviders.Embedded.Manifest.Task.Tests.csproj
@@ -1,7 +1,7 @@
- netcoreapp2.2;net461
+ netcoreapp3.0
@@ -9,16 +9,8 @@
-
-
-
-
-
-
-
-
diff --git a/src/HealthChecks/Abstractions/Directory.Build.props b/src/HealthChecks/Abstractions/Directory.Build.props
deleted file mode 100644
index f25c1d90ce..0000000000
--- a/src/HealthChecks/Abstractions/Directory.Build.props
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
- true
-
-
diff --git a/src/HealthChecks/Abstractions/ref/Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions.csproj b/src/HealthChecks/Abstractions/ref/Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions.csproj
new file mode 100644
index 0000000000..be23858955
--- /dev/null
+++ b/src/HealthChecks/Abstractions/ref/Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions.csproj
@@ -0,0 +1,10 @@
+
+
+
+ netstandard2.0
+
+
+
+
+
+
diff --git a/src/HealthChecks/Abstractions/ref/Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions.netstandard2.0.cs b/src/HealthChecks/Abstractions/ref/Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions.netstandard2.0.cs
new file mode 100644
index 0000000000..9ab497257e
--- /dev/null
+++ b/src/HealthChecks/Abstractions/ref/Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions.netstandard2.0.cs
@@ -0,0 +1,70 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Microsoft.Extensions.Diagnostics.HealthChecks
+{
+ public sealed partial class HealthCheckContext
+ {
+ public HealthCheckContext() { }
+ public Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckRegistration Registration { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
+ }
+ public sealed partial class HealthCheckRegistration
+ {
+ public HealthCheckRegistration(string name, Microsoft.Extensions.Diagnostics.HealthChecks.IHealthCheck instance, Microsoft.Extensions.Diagnostics.HealthChecks.HealthStatus? failureStatus, System.Collections.Generic.IEnumerable tags) { }
+ public HealthCheckRegistration(string name, Microsoft.Extensions.Diagnostics.HealthChecks.IHealthCheck instance, Microsoft.Extensions.Diagnostics.HealthChecks.HealthStatus? failureStatus, System.Collections.Generic.IEnumerable tags, System.TimeSpan? timeout) { }
+ public HealthCheckRegistration(string name, System.Func factory, Microsoft.Extensions.Diagnostics.HealthChecks.HealthStatus? failureStatus, System.Collections.Generic.IEnumerable tags) { }
+ public HealthCheckRegistration(string name, System.Func factory, Microsoft.Extensions.Diagnostics.HealthChecks.HealthStatus? failureStatus, System.Collections.Generic.IEnumerable tags, System.TimeSpan? timeout) { }
+ public System.Func Factory { get { throw null; } set { } }
+ public Microsoft.Extensions.Diagnostics.HealthChecks.HealthStatus FailureStatus { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
+ public string Name { get { throw null; } set { } }
+ public System.Collections.Generic.ISet Tags { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
+ public System.TimeSpan Timeout { get { throw null; } set { } }
+ }
+ [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
+ public partial struct HealthCheckResult
+ {
+ private object _dummy;
+ private int _dummyPrimitive;
+ public HealthCheckResult(Microsoft.Extensions.Diagnostics.HealthChecks.HealthStatus status, string description = null, System.Exception exception = null, System.Collections.Generic.IReadOnlyDictionary data = null) { throw null; }
+ public System.Collections.Generic.IReadOnlyDictionary Data { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
+ public string Description { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
+ public System.Exception Exception { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
+ public Microsoft.Extensions.Diagnostics.HealthChecks.HealthStatus Status { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
+ public static Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckResult Degraded(string description = null, System.Exception exception = null, System.Collections.Generic.IReadOnlyDictionary data = null) { throw null; }
+ public static Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckResult Healthy(string description = null, System.Collections.Generic.IReadOnlyDictionary data = null) { throw null; }
+ public static Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckResult Unhealthy(string description = null, System.Exception exception = null, System.Collections.Generic.IReadOnlyDictionary data = null) { throw null; }
+ }
+ public sealed partial class HealthReport
+ {
+ public HealthReport(System.Collections.Generic.IReadOnlyDictionary entries, System.TimeSpan totalDuration) { }
+ public System.Collections.Generic.IReadOnlyDictionary Entries { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
+ public Microsoft.Extensions.Diagnostics.HealthChecks.HealthStatus Status { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
+ public System.TimeSpan TotalDuration { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
+ }
+ [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
+ public partial struct HealthReportEntry
+ {
+ private object _dummy;
+ private int _dummyPrimitive;
+ public HealthReportEntry(Microsoft.Extensions.Diagnostics.HealthChecks.HealthStatus status, string description, System.TimeSpan duration, System.Exception exception, System.Collections.Generic.IReadOnlyDictionary data) { throw null; }
+ public System.Collections.Generic.IReadOnlyDictionary Data { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
+ public string Description { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
+ public System.TimeSpan Duration { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
+ public System.Exception Exception { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
+ public Microsoft.Extensions.Diagnostics.HealthChecks.HealthStatus Status { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
+ }
+ public enum HealthStatus
+ {
+ Degraded = 1,
+ Healthy = 2,
+ Unhealthy = 0,
+ }
+ public partial interface IHealthCheck
+ {
+ System.Threading.Tasks.Task CheckHealthAsync(Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckContext context, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken));
+ }
+ public partial interface IHealthCheckPublisher
+ {
+ System.Threading.Tasks.Task PublishAsync(Microsoft.Extensions.Diagnostics.HealthChecks.HealthReport report, System.Threading.CancellationToken cancellationToken);
+ }
+}
diff --git a/src/HealthChecks/Abstractions/src/HealthCheckRegistration.cs b/src/HealthChecks/Abstractions/src/HealthCheckRegistration.cs
index 9291c38846..8ee11e3195 100644
--- a/src/HealthChecks/Abstractions/src/HealthCheckRegistration.cs
+++ b/src/HealthChecks/Abstractions/src/HealthCheckRegistration.cs
@@ -1,4 +1,4 @@
-// Copyright (c) .NET Foundation. All rights reserved.
+// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
@@ -24,6 +24,22 @@ namespace Microsoft.Extensions.Diagnostics.HealthChecks
{
private Func _factory;
private string _name;
+ private TimeSpan _timeout;
+
+ ///
+ /// Creates a new for an existing instance.
+ ///
+ /// The health check name.
+ /// The instance.
+ ///
+ /// The that should be reported upon failure of the health check. If the provided value
+ /// is null, then will be reported.
+ ///
+ /// A list of tags that can be used for filtering health checks.
+ public HealthCheckRegistration(string name, IHealthCheck instance, HealthStatus? failureStatus, IEnumerable tags)
+ : this(name, instance, failureStatus, tags, default)
+ {
+ }
///
/// Creates a new for an existing instance.
@@ -35,7 +51,8 @@ namespace Microsoft.Extensions.Diagnostics.HealthChecks
/// is null, then will be reported.
///
/// A list of tags that can be used for filtering health checks.
- public HealthCheckRegistration(string name, IHealthCheck instance, HealthStatus? failureStatus, IEnumerable tags)
+ /// An optional representing the timeout of the check.
+ public HealthCheckRegistration(string name, IHealthCheck instance, HealthStatus? failureStatus, IEnumerable tags, TimeSpan? timeout)
{
if (name == null)
{
@@ -47,10 +64,16 @@ namespace Microsoft.Extensions.Diagnostics.HealthChecks
throw new ArgumentNullException(nameof(instance));
}
+ if (timeout <= TimeSpan.Zero && timeout != System.Threading.Timeout.InfiniteTimeSpan)
+ {
+ throw new ArgumentOutOfRangeException(nameof(timeout));
+ }
+
Name = name;
FailureStatus = failureStatus ?? HealthStatus.Unhealthy;
Tags = new HashSet(tags ?? Array.Empty(), StringComparer.OrdinalIgnoreCase);
Factory = (_) => instance;
+ Timeout = timeout ?? System.Threading.Timeout.InfiniteTimeSpan;
}
///
@@ -68,6 +91,27 @@ namespace Microsoft.Extensions.Diagnostics.HealthChecks
Func factory,
HealthStatus? failureStatus,
IEnumerable tags)
+ : this(name, factory, failureStatus, tags, default)
+ {
+ }
+
+ ///
+ /// Creates a new for an existing instance.
+ ///
+ /// The health check name.
+ /// A delegate used to create the instance.
+ ///
+ /// The that should be reported when the health check reports a failure. If the provided value
+ /// is null, then will be reported.
+ ///
+ /// A list of tags that can be used for filtering health checks.
+ /// An optional representing the timeout of the check.
+ public HealthCheckRegistration(
+ string name,
+ Func factory,
+ HealthStatus? failureStatus,
+ IEnumerable tags,
+ TimeSpan? timeout)
{
if (name == null)
{
@@ -79,10 +123,16 @@ namespace Microsoft.Extensions.Diagnostics.HealthChecks
throw new ArgumentNullException(nameof(factory));
}
+ if (timeout <= TimeSpan.Zero && timeout != System.Threading.Timeout.InfiniteTimeSpan)
+ {
+ throw new ArgumentOutOfRangeException(nameof(timeout));
+ }
+
Name = name;
FailureStatus = failureStatus ?? HealthStatus.Unhealthy;
Tags = new HashSet(tags ?? Array.Empty(), StringComparer.OrdinalIgnoreCase);
Factory = factory;
+ Timeout = timeout ?? System.Threading.Timeout.InfiniteTimeSpan;
}
///
@@ -107,6 +157,23 @@ namespace Microsoft.Extensions.Diagnostics.HealthChecks
///
public HealthStatus FailureStatus { get; set; }
+ ///
+ /// Gets or sets the timeout used for the test.
+ ///
+ public TimeSpan Timeout
+ {
+ get => _timeout;
+ set
+ {
+ if (value <= TimeSpan.Zero && value != System.Threading.Timeout.InfiniteTimeSpan)
+ {
+ throw new ArgumentOutOfRangeException(nameof(value));
+ }
+
+ _timeout = value;
+ }
+ }
+
///
/// Gets or sets the health check name.
///
diff --git a/src/HealthChecks/Abstractions/src/HealthCheckResult.cs b/src/HealthChecks/Abstractions/src/HealthCheckResult.cs
index e01cb5aceb..7f4522da19 100644
--- a/src/HealthChecks/Abstractions/src/HealthCheckResult.cs
+++ b/src/HealthChecks/Abstractions/src/HealthCheckResult.cs
@@ -70,7 +70,7 @@ namespace Microsoft.Extensions.Diagnostics.HealthChecks
/// A representing a degraged component.
public static HealthCheckResult Degraded(string description = null, Exception exception = null, IReadOnlyDictionary data = null)
{
- return new HealthCheckResult(status: HealthStatus.Degraded, description, exception: null, data);
+ return new HealthCheckResult(status: HealthStatus.Degraded, description, exception: exception, data);
}
///
diff --git a/src/HealthChecks/Abstractions/src/Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions.csproj b/src/HealthChecks/Abstractions/src/Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions.csproj
index b95d66f7b3..2bba5959a3 100644
--- a/src/HealthChecks/Abstractions/src/Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions.csproj
+++ b/src/HealthChecks/Abstractions/src/Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions.csproj
@@ -11,6 +11,7 @@ Microsoft.Extensions.Diagnostics.HealthChecks.IHealthCheck
$(NoWarn);CS1591
true
diagnostics;healthchecks
+ true
diff --git a/src/HealthChecks/Abstractions/src/baseline.netcore.json b/src/HealthChecks/Abstractions/src/baseline.netcore.json
deleted file mode 100644
index 871db4c089..0000000000
--- a/src/HealthChecks/Abstractions/src/baseline.netcore.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "AssemblyIdentity": "Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60",
- "Types": [
- ]
-}
\ No newline at end of file
diff --git a/src/HealthChecks/HealthChecks/Directory.Build.props b/src/HealthChecks/HealthChecks/Directory.Build.props
deleted file mode 100644
index f25c1d90ce..0000000000
--- a/src/HealthChecks/HealthChecks/Directory.Build.props
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
- true
-
-
diff --git a/src/HealthChecks/HealthChecks/ref/Microsoft.Extensions.Diagnostics.HealthChecks.csproj b/src/HealthChecks/HealthChecks/ref/Microsoft.Extensions.Diagnostics.HealthChecks.csproj
new file mode 100644
index 0000000000..277e60910f
--- /dev/null
+++ b/src/HealthChecks/HealthChecks/ref/Microsoft.Extensions.Diagnostics.HealthChecks.csproj
@@ -0,0 +1,12 @@
+
+
+
+ netstandard2.0
+
+
+
+
+
+
+
+
diff --git a/src/HealthChecks/HealthChecks/ref/Microsoft.Extensions.Diagnostics.HealthChecks.netstandard2.0.cs b/src/HealthChecks/HealthChecks/ref/Microsoft.Extensions.Diagnostics.HealthChecks.netstandard2.0.cs
new file mode 100644
index 0000000000..a23961efdd
--- /dev/null
+++ b/src/HealthChecks/HealthChecks/ref/Microsoft.Extensions.Diagnostics.HealthChecks.netstandard2.0.cs
@@ -0,0 +1,59 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Microsoft.Extensions.DependencyInjection
+{
+ public static partial class HealthChecksBuilderAddCheckExtensions
+ {
+ public static Microsoft.Extensions.DependencyInjection.IHealthChecksBuilder AddCheck(this Microsoft.Extensions.DependencyInjection.IHealthChecksBuilder builder, string name, Microsoft.Extensions.Diagnostics.HealthChecks.IHealthCheck instance, Microsoft.Extensions.Diagnostics.HealthChecks.HealthStatus? failureStatus, System.Collections.Generic.IEnumerable tags) { throw null; }
+ public static Microsoft.Extensions.DependencyInjection.IHealthChecksBuilder AddCheck(this Microsoft.Extensions.DependencyInjection.IHealthChecksBuilder builder, string name, Microsoft.Extensions.Diagnostics.HealthChecks.IHealthCheck instance, Microsoft.Extensions.Diagnostics.HealthChecks.HealthStatus? failureStatus = default(Microsoft.Extensions.Diagnostics.HealthChecks.HealthStatus?), System.Collections.Generic.IEnumerable tags = null, System.TimeSpan? timeout = default(System.TimeSpan?)) { throw null; }
+ public static Microsoft.Extensions.DependencyInjection.IHealthChecksBuilder AddCheck(this Microsoft.Extensions.DependencyInjection.IHealthChecksBuilder builder, string name, Microsoft.Extensions.Diagnostics.HealthChecks.HealthStatus? failureStatus, System.Collections.Generic.IEnumerable tags) where T : class, Microsoft.Extensions.Diagnostics.HealthChecks.IHealthCheck { throw null; }
+ public static Microsoft.Extensions.DependencyInjection.IHealthChecksBuilder AddCheck(this Microsoft.Extensions.DependencyInjection.IHealthChecksBuilder builder, string name, Microsoft.Extensions.Diagnostics.HealthChecks.HealthStatus? failureStatus = default(Microsoft.Extensions.Diagnostics.HealthChecks.HealthStatus?), System.Collections.Generic.IEnumerable tags = null, System.TimeSpan? timeout = default(System.TimeSpan?)) where T : class, Microsoft.Extensions.Diagnostics.HealthChecks.IHealthCheck { throw null; }
+ public static Microsoft.Extensions.DependencyInjection.IHealthChecksBuilder AddTypeActivatedCheck(this Microsoft.Extensions.DependencyInjection.IHealthChecksBuilder builder, string name, Microsoft.Extensions.Diagnostics.HealthChecks.HealthStatus? failureStatus, System.Collections.Generic.IEnumerable tags, params object[] args) where T : class, Microsoft.Extensions.Diagnostics.HealthChecks.IHealthCheck { throw null; }
+ public static Microsoft.Extensions.DependencyInjection.IHealthChecksBuilder AddTypeActivatedCheck(this Microsoft.Extensions.DependencyInjection.IHealthChecksBuilder builder, string name, Microsoft.Extensions.Diagnostics.HealthChecks.HealthStatus? failureStatus, System.Collections.Generic.IEnumerable tags, System.TimeSpan timeout, params object[] args) where T : class, Microsoft.Extensions.Diagnostics.HealthChecks.IHealthCheck { throw null; }
+ public static Microsoft.Extensions.DependencyInjection.IHealthChecksBuilder AddTypeActivatedCheck(this Microsoft.Extensions.DependencyInjection.IHealthChecksBuilder builder, string name, Microsoft.Extensions.Diagnostics.HealthChecks.HealthStatus? failureStatus, params object[] args) where T : class, Microsoft.Extensions.Diagnostics.HealthChecks.IHealthCheck { throw null; }
+ public static Microsoft.Extensions.DependencyInjection.IHealthChecksBuilder AddTypeActivatedCheck(this Microsoft.Extensions.DependencyInjection.IHealthChecksBuilder builder, string name, params object[] args) where T : class, Microsoft.Extensions.Diagnostics.HealthChecks.IHealthCheck { throw null; }
+ }
+ public static partial class HealthChecksBuilderDelegateExtensions
+ {
+ public static Microsoft.Extensions.DependencyInjection.IHealthChecksBuilder AddAsyncCheck(this Microsoft.Extensions.DependencyInjection.IHealthChecksBuilder builder, string name, System.Func> check, System.Collections.Generic.IEnumerable tags) { throw null; }
+ public static Microsoft.Extensions.DependencyInjection.IHealthChecksBuilder AddAsyncCheck(this Microsoft.Extensions.DependencyInjection.IHealthChecksBuilder builder, string name, System.Func> check, System.Collections.Generic.IEnumerable tags = null, System.TimeSpan? timeout = default(System.TimeSpan?)) { throw null; }
+ public static Microsoft.Extensions.DependencyInjection.IHealthChecksBuilder AddAsyncCheck(this Microsoft.Extensions.DependencyInjection.IHealthChecksBuilder builder, string name, System.Func> check, System.Collections.Generic.IEnumerable tags) { throw null; }
+ public static Microsoft.Extensions.DependencyInjection.IHealthChecksBuilder AddAsyncCheck(this Microsoft.Extensions.DependencyInjection.IHealthChecksBuilder builder, string name, System.Func> check, System.Collections.Generic.IEnumerable tags = null, System.TimeSpan? timeout = default(System.TimeSpan?)) { throw null; }
+ public static Microsoft.Extensions.DependencyInjection.IHealthChecksBuilder AddCheck(this Microsoft.Extensions.DependencyInjection.IHealthChecksBuilder builder, string name, System.Func check, System.Collections.Generic.IEnumerable tags) { throw null; }
+ public static Microsoft.Extensions.DependencyInjection.IHealthChecksBuilder AddCheck(this Microsoft.Extensions.DependencyInjection.IHealthChecksBuilder builder, string name, System.Func check, System.Collections.Generic.IEnumerable tags = null, System.TimeSpan? timeout = default(System.TimeSpan?)) { throw null; }
+ public static Microsoft.Extensions.DependencyInjection.IHealthChecksBuilder AddCheck(this Microsoft.Extensions.DependencyInjection.IHealthChecksBuilder builder, string name, System.Func check, System.Collections.Generic.IEnumerable tags) { throw null; }
+ public static Microsoft.Extensions.DependencyInjection.IHealthChecksBuilder AddCheck(this Microsoft.Extensions.DependencyInjection.IHealthChecksBuilder builder, string name, System.Func check, System.Collections.Generic.IEnumerable tags = null, System.TimeSpan? timeout = default(System.TimeSpan?)) { throw null; }
+ }
+ public static partial class HealthCheckServiceCollectionExtensions
+ {
+ public static Microsoft.Extensions.DependencyInjection.IHealthChecksBuilder AddHealthChecks(this Microsoft.Extensions.DependencyInjection.IServiceCollection services) { throw null; }
+ }
+ public partial interface IHealthChecksBuilder
+ {
+ Microsoft.Extensions.DependencyInjection.IServiceCollection Services { get; }
+ Microsoft.Extensions.DependencyInjection.IHealthChecksBuilder Add(Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckRegistration registration);
+ }
+}
+namespace Microsoft.Extensions.Diagnostics.HealthChecks
+{
+ public sealed partial class HealthCheckPublisherOptions
+ {
+ public HealthCheckPublisherOptions() { }
+ public System.TimeSpan Delay { get { throw null; } set { } }
+ public System.TimeSpan Period { get { throw null; } set { } }
+ public System.Func Predicate { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
+ public System.TimeSpan Timeout { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
+ }
+ public abstract partial class HealthCheckService
+ {
+ protected HealthCheckService() { }
+ public abstract System.Threading.Tasks.Task CheckHealthAsync(System.Func predicate, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken));
+ public System.Threading.Tasks.Task CheckHealthAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
+ }
+ public sealed partial class HealthCheckServiceOptions
+ {
+ public HealthCheckServiceOptions() { }
+ public System.Collections.Generic.ICollection Registrations { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
+ }
+}
diff --git a/src/HealthChecks/HealthChecks/src/DefaultHealthCheckService.cs b/src/HealthChecks/HealthChecks/src/DefaultHealthCheckService.cs
index d5d71d9cb4..56ce966d18 100644
--- a/src/HealthChecks/HealthChecks/src/DefaultHealthCheckService.cs
+++ b/src/HealthChecks/HealthChecks/src/DefaultHealthCheckService.cs
@@ -40,74 +40,118 @@ namespace Microsoft.Extensions.Diagnostics.HealthChecks
CancellationToken cancellationToken = default)
{
var registrations = _options.Value.Registrations;
+ if (predicate != null)
+ {
+ registrations = registrations.Where(predicate).ToArray();
+ }
+ var totalTime = ValueStopwatch.StartNew();
+ Log.HealthCheckProcessingBegin(_logger);
+
+ var tasks = new Task[registrations.Count];
+ var index = 0;
using (var scope = _scopeFactory.CreateScope())
{
- var context = new HealthCheckContext();
- var entries = new Dictionary(StringComparer.OrdinalIgnoreCase);
-
- var totalTime = ValueStopwatch.StartNew();
- Log.HealthCheckProcessingBegin(_logger);
-
foreach (var registration in registrations)
{
- if (predicate != null && !predicate(registration))
- {
- continue;
- }
-
- cancellationToken.ThrowIfCancellationRequested();
-
- var healthCheck = registration.Factory(scope.ServiceProvider);
-
- // If the health check does things like make Database queries using EF or backend HTTP calls,
- // it may be valuable to know that logs it generates are part of a health check. So we start a scope.
- using (_logger.BeginScope(new HealthCheckLogScope(registration.Name)))
- {
- var stopwatch = ValueStopwatch.StartNew();
- context.Registration = registration;
-
- Log.HealthCheckBegin(_logger, registration);
-
- HealthReportEntry entry;
- try
- {
- var result = await healthCheck.CheckHealthAsync(context, cancellationToken);
- var duration = stopwatch.GetElapsedTime();
-
- entry = new HealthReportEntry(
- status: result.Status,
- description: result.Description,
- duration: duration,
- exception: result.Exception,
- data: result.Data);
-
- Log.HealthCheckEnd(_logger, registration, entry, duration);
- Log.HealthCheckData(_logger, registration, entry);
- }
-
- // Allow cancellation to propagate.
- catch (Exception ex) when (ex as OperationCanceledException == null)
- {
- var duration = stopwatch.GetElapsedTime();
- entry = new HealthReportEntry(
- status: HealthStatus.Unhealthy,
- description: ex.Message,
- duration: duration,
- exception: ex,
- data: null);
-
- Log.HealthCheckError(_logger, registration, ex, duration);
- }
-
- entries[registration.Name] = entry;
- }
+ tasks[index++] = RunCheckAsync(scope, registration, cancellationToken);
}
- var totalElapsedTime = totalTime.GetElapsedTime();
- var report = new HealthReport(entries, totalElapsedTime);
- Log.HealthCheckProcessingEnd(_logger, report.Status, totalElapsedTime);
- return report;
+ await Task.WhenAll(tasks).ConfigureAwait(false);
+ }
+
+ index = 0;
+ var entries = new Dictionary(StringComparer.OrdinalIgnoreCase);
+ foreach (var registration in registrations)
+ {
+ entries[registration.Name] = tasks[index++].Result;
+ }
+
+ var totalElapsedTime = totalTime.GetElapsedTime();
+ var report = new HealthReport(entries, totalElapsedTime);
+ Log.HealthCheckProcessingEnd(_logger, report.Status, totalElapsedTime);
+ return report;
+ }
+
+ private async Task RunCheckAsync(IServiceScope scope, HealthCheckRegistration registration, CancellationToken cancellationToken)
+ {
+ await Task.Yield();
+
+ cancellationToken.ThrowIfCancellationRequested();
+
+ var healthCheck = registration.Factory(scope.ServiceProvider);
+
+ // If the health check does things like make Database queries using EF or backend HTTP calls,
+ // it may be valuable to know that logs it generates are part of a health check. So we start a scope.
+ using (_logger.BeginScope(new HealthCheckLogScope(registration.Name)))
+ {
+ var stopwatch = ValueStopwatch.StartNew();
+ var context = new HealthCheckContext { Registration = registration };
+
+ Log.HealthCheckBegin(_logger, registration);
+
+ HealthReportEntry entry;
+ CancellationTokenSource timeoutCancellationTokenSource = null;
+ try
+ {
+ HealthCheckResult result;
+
+ var checkCancellationToken = cancellationToken;
+ if (registration.Timeout > TimeSpan.Zero)
+ {
+ timeoutCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
+ timeoutCancellationTokenSource.CancelAfter(registration.Timeout);
+ checkCancellationToken = timeoutCancellationTokenSource.Token;
+ }
+
+ result = await healthCheck.CheckHealthAsync(context, checkCancellationToken);
+
+ var duration = stopwatch.GetElapsedTime();
+
+ entry = new HealthReportEntry(
+ status: result.Status,
+ description: result.Description,
+ duration: duration,
+ exception: result.Exception,
+ data: result.Data);
+
+ Log.HealthCheckEnd(_logger, registration, entry, duration);
+ Log.HealthCheckData(_logger, registration, entry);
+ }
+
+ catch (OperationCanceledException ex) when (!cancellationToken.IsCancellationRequested)
+ {
+ var duration = stopwatch.GetElapsedTime();
+ entry = new HealthReportEntry(
+ status: HealthStatus.Unhealthy,
+ description: "A timeout occured while running check.",
+ duration: duration,
+ exception: ex,
+ data: null);
+
+ Log.HealthCheckError(_logger, registration, ex, duration);
+ }
+
+ // Allow cancellation to propagate if it's not a timeout.
+ catch (Exception ex) when (ex as OperationCanceledException == null)
+ {
+ var duration = stopwatch.GetElapsedTime();
+ entry = new HealthReportEntry(
+ status: HealthStatus.Unhealthy,
+ description: ex.Message,
+ duration: duration,
+ exception: ex,
+ data: null);
+
+ Log.HealthCheckError(_logger, registration, ex, duration);
+ }
+
+ finally
+ {
+ timeoutCancellationTokenSource?.Dispose();
+ }
+
+ return entry;
}
}
diff --git a/src/HealthChecks/HealthChecks/src/DependencyInjection/HealthCheckServiceCollectionExtensions.cs b/src/HealthChecks/HealthChecks/src/DependencyInjection/HealthCheckServiceCollectionExtensions.cs
index d6df03d2ae..91ffa59449 100644
--- a/src/HealthChecks/HealthChecks/src/DependencyInjection/HealthCheckServiceCollectionExtensions.cs
+++ b/src/HealthChecks/HealthChecks/src/DependencyInjection/HealthCheckServiceCollectionExtensions.cs
@@ -26,7 +26,7 @@ namespace Microsoft.Extensions.DependencyInjection
public static IHealthChecksBuilder AddHealthChecks(this IServiceCollection services)
{
services.TryAddSingleton();
- services.TryAddSingleton();
+ services.TryAddEnumerable(ServiceDescriptor.Singleton());
return new HealthChecksBuilder(services);
}
}
diff --git a/src/HealthChecks/HealthChecks/src/DependencyInjection/HealthChecksBuilderAddCheckExtensions.cs b/src/HealthChecks/HealthChecks/src/DependencyInjection/HealthChecksBuilderAddCheckExtensions.cs
index 9508889054..51b7815438 100644
--- a/src/HealthChecks/HealthChecks/src/DependencyInjection/HealthChecksBuilderAddCheckExtensions.cs
+++ b/src/HealthChecks/HealthChecks/src/DependencyInjection/HealthChecksBuilderAddCheckExtensions.cs
@@ -24,12 +24,37 @@ namespace Microsoft.Extensions.DependencyInjection
///
/// A list of tags that can be used to filter health checks.
/// The .
+ // 2.0 BACKCOMPAT OVERLOAD -- DO NOT TOUCH
+ public static IHealthChecksBuilder AddCheck(
+ this IHealthChecksBuilder builder,
+ string name,
+ IHealthCheck instance,
+ HealthStatus? failureStatus,
+ IEnumerable tags)
+ {
+ return AddCheck(builder, name, instance, failureStatus, tags, default);
+ }
+
+ ///
+ /// Adds a new health check with the specified name and implementation.
+ ///
+ /// The .
+ /// The name of the health check.
+ /// An instance.
+ ///
+ /// The that should be reported when the health check reports a failure. If the provided value
+ /// is null, then will be reported.
+ ///
+ /// A list of tags that can be used to filter health checks.
+ /// An optional representing the timeout of the check.
+ /// The .
public static IHealthChecksBuilder AddCheck(
this IHealthChecksBuilder builder,
string name,
IHealthCheck instance,
HealthStatus? failureStatus = null,
- IEnumerable tags = null)
+ IEnumerable tags = null,
+ TimeSpan? timeout = null)
{
if (builder == null)
{
@@ -46,7 +71,7 @@ namespace Microsoft.Extensions.DependencyInjection
throw new ArgumentNullException(nameof(instance));
}
- return builder.Add(new HealthCheckRegistration(name, instance, failureStatus, tags));
+ return builder.Add(new HealthCheckRegistration(name, instance, failureStatus, tags, timeout));
}
///
@@ -63,15 +88,45 @@ namespace Microsoft.Extensions.DependencyInjection
/// The .
///
/// This method will use to create the health check
- /// instance when needed. If a service of type is registred in the dependency injection container
- /// with any liftime it will be used. Otherwise an instance of type will be constructed with
+ /// instance when needed. If a service of type is registered in the dependency injection container
+ /// with any lifetime it will be used. Otherwise an instance of type will be constructed with
+ /// access to services from the dependency injection container.
+ ///
+ // 2.0 BACKCOMPAT OVERLOAD -- DO NOT TOUCH
+ public static IHealthChecksBuilder AddCheck(
+ this IHealthChecksBuilder builder,
+ string name,
+ HealthStatus? failureStatus,
+ IEnumerable tags) where T : class, IHealthCheck
+ {
+ return AddCheck(builder, name, failureStatus, tags, default);
+ }
+
+ ///
+ /// Adds a new health check with the specified name and implementation.
+ ///
+ /// The health check implementation type.
+ /// The .
+ /// The name of the health check.
+ ///
+ /// The that should be reported when the health check reports a failure. If the provided value
+ /// is null, then will be reported.
+ ///
+ /// A list of tags that can be used to filter health checks.
+ /// An optional representing the timeout of the check.
+ /// The .
+ ///
+ /// This method will use to create the health check
+ /// instance when needed. If a service of type is registered in the dependency injection container
+ /// with any lifetime it will be used. Otherwise an instance of type will be constructed with
/// access to services from the dependency injection container.
///
public static IHealthChecksBuilder AddCheck(
this IHealthChecksBuilder builder,
string name,
HealthStatus? failureStatus = null,
- IEnumerable tags = null) where T : class, IHealthCheck
+ IEnumerable tags = null,
+ TimeSpan? timeout = null) where T : class, IHealthCheck
{
if (builder == null)
{
@@ -83,7 +138,7 @@ namespace Microsoft.Extensions.DependencyInjection
throw new ArgumentNullException(nameof(name));
}
- return builder.Add(new HealthCheckRegistration(name, s => ActivatorUtilities.GetServiceOrCreateInstance(s), failureStatus, tags));
+ return builder.Add(new HealthCheckRegistration(name, s => ActivatorUtilities.GetServiceOrCreateInstance(s), failureStatus, tags, timeout));
}
// NOTE: AddTypeActivatedCheck has overloads rather than default parameters values, because default parameter values don't
@@ -113,7 +168,7 @@ namespace Microsoft.Extensions.DependencyInjection
throw new ArgumentNullException(nameof(name));
}
- return AddTypeActivatedCheck(builder, name, failureStatus: null, tags: null);
+ return AddTypeActivatedCheck(builder, name, failureStatus: null, tags: null, args);
}
///
@@ -148,7 +203,7 @@ namespace Microsoft.Extensions.DependencyInjection
throw new ArgumentNullException(nameof(name));
}
- return AddTypeActivatedCheck(builder, name, failureStatus, tags: null);
+ return AddTypeActivatedCheck(builder, name, failureStatus, tags: null, args);
}
///
@@ -187,5 +242,44 @@ namespace Microsoft.Extensions.DependencyInjection
return builder.Add(new HealthCheckRegistration(name, s => ActivatorUtilities.CreateInstance(s, args), failureStatus, tags));
}
+
+ ///
+ /// Adds a new type activated health check with the specified name and implementation.
+ ///
+ /// The health check implementation type.
+ /// The .
+ /// The name of the health check.
+ ///
+ /// The that should be reported when the health check reports a failure. If the provided value
+ /// is null, then will be reported.
+ ///
+ /// A list of tags that can be used to filter health checks.
+ /// Additional arguments to provide to the constructor.
+ /// A representing the timeout of the check.
+ /// The .
+ ///
+ /// This method will use to create the health check
+ /// instance when needed. Additional arguments can be provided to the constructor via .
+ ///
+ public static IHealthChecksBuilder AddTypeActivatedCheck(
+ this IHealthChecksBuilder builder,
+ string name,
+ HealthStatus? failureStatus,
+ IEnumerable tags,
+ TimeSpan timeout,
+ params object[] args) where T : class, IHealthCheck
+ {
+ if (builder == null)
+ {
+ throw new ArgumentNullException(nameof(builder));
+ }
+
+ if (name == null)
+ {
+ throw new ArgumentNullException(nameof(name));
+ }
+
+ return builder.Add(new HealthCheckRegistration(name, s => ActivatorUtilities.CreateInstance(s, args), failureStatus, tags, timeout));
+ }
}
}
diff --git a/src/HealthChecks/HealthChecks/src/DependencyInjection/HealthChecksBuilderDelegateExtensions.cs b/src/HealthChecks/HealthChecks/src/DependencyInjection/HealthChecksBuilderDelegateExtensions.cs
index d7dfdd90ae..ba27ab5554 100644
--- a/src/HealthChecks/HealthChecks/src/DependencyInjection/HealthChecksBuilderDelegateExtensions.cs
+++ b/src/HealthChecks/HealthChecks/src/DependencyInjection/HealthChecksBuilderDelegateExtensions.cs
@@ -1,4 +1,4 @@
-// Copyright (c) .NET Foundation. All rights reserved.
+// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
@@ -22,11 +22,31 @@ namespace Microsoft.Extensions.DependencyInjection
/// A list of tags that can be used to filter health checks.
/// A delegate that provides the health check implementation.
/// The .
+ // 2.0 BACKCOMPAT OVERLOAD -- DO NOT TOUCH
public static IHealthChecksBuilder AddCheck(
this IHealthChecksBuilder builder,
string name,
Func check,
- IEnumerable tags = null)
+ IEnumerable tags)
+ {
+ return AddCheck(builder, name, check, tags, default);
+ }
+
+ ///
+ /// Adds a new health check with the specified name and implementation.
+ ///
+ /// The .
+ /// The name of the health check.
+ /// A list of tags that can be used to filter health checks.
+ /// A delegate that provides the health check implementation.
+ /// An optional representing the timeout of the check.
+ /// The .
+ public static IHealthChecksBuilder AddCheck(
+ this IHealthChecksBuilder builder,
+ string name,
+ Func check,
+ IEnumerable tags = null,
+ TimeSpan? timeout = default)
{
if (builder == null)
{
@@ -44,7 +64,7 @@ namespace Microsoft.Extensions.DependencyInjection
}
var instance = new DelegateHealthCheck((ct) => Task.FromResult(check()));
- return builder.Add(new HealthCheckRegistration(name, instance, failureStatus: null, tags));
+ return builder.Add(new HealthCheckRegistration(name, instance, failureStatus: null, tags, timeout));
}
///
@@ -55,11 +75,31 @@ namespace Microsoft.Extensions.DependencyInjection
/// A list of tags that can be used to filter health checks.
/// A delegate that provides the health check implementation.
/// The .
+ // 2.0 BACKCOMPAT OVERLOAD -- DO NOT TOUCH
public static IHealthChecksBuilder AddCheck(
this IHealthChecksBuilder builder,
string name,
Func check,
- IEnumerable tags = null)
+ IEnumerable tags)
+ {
+ return AddCheck(builder, name, check, tags, default);
+ }
+
+ ///
+ /// Adds a new health check with the specified name and implementation.
+ ///
+ /// The .
+ /// The name of the health check.
+ /// A list of tags that can be used to filter health checks.
+ /// A delegate that provides the health check implementation.
+ /// An optional representing the timeout of the check.
+ /// The .
+ public static IHealthChecksBuilder AddCheck(
+ this IHealthChecksBuilder builder,
+ string name,
+ Func check,
+ IEnumerable tags = null,
+ TimeSpan? timeout = default)
{
if (builder == null)
{
@@ -77,7 +117,7 @@ namespace Microsoft.Extensions.DependencyInjection
}
var instance = new DelegateHealthCheck((ct) => Task.FromResult(check(ct)));
- return builder.Add(new HealthCheckRegistration(name, instance, failureStatus: null, tags));
+ return builder.Add(new HealthCheckRegistration(name, instance, failureStatus: null, tags, timeout));
}
///
@@ -88,11 +128,31 @@ namespace Microsoft.Extensions.DependencyInjection
/// A list of tags that can be used to filter health checks.
/// A delegate that provides the health check implementation.
/// The .
+ // 2.0 BACKCOMPAT OVERLOAD -- DO NOT TOUCH
public static IHealthChecksBuilder AddAsyncCheck(
this IHealthChecksBuilder builder,
string name,
Func> check,
- IEnumerable tags = null)
+ IEnumerable tags)
+ {
+ return AddAsyncCheck(builder, name, check, tags, default);
+ }
+
+ ///
+ /// Adds a new health check with the specified name and implementation.
+ ///
+ /// The .
+ /// The name of the health check.
+ /// A list of tags that can be used to filter health checks.
+ /// A delegate that provides the health check implementation.
+ /// An optional representing the timeout of the check.
+ /// The .
+ public static IHealthChecksBuilder AddAsyncCheck(
+ this IHealthChecksBuilder builder,
+ string name,
+ Func> check,
+ IEnumerable tags = null,
+ TimeSpan? timeout = default)
{
if (builder == null)
{
@@ -110,7 +170,7 @@ namespace Microsoft.Extensions.DependencyInjection
}
var instance = new DelegateHealthCheck((ct) => check());
- return builder.Add(new HealthCheckRegistration(name, instance, failureStatus: null, tags));
+ return builder.Add(new HealthCheckRegistration(name, instance, failureStatus: null, tags, timeout));
}
///
@@ -121,11 +181,31 @@ namespace Microsoft.Extensions.DependencyInjection
/// A list of tags that can be used to filter health checks.
/// A delegate that provides the health check implementation.
/// The .
+ // 2.0 BACKCOMPAT OVERLOAD -- DO NOT TOUCH
public static IHealthChecksBuilder AddAsyncCheck(
this IHealthChecksBuilder builder,
string name,
Func> check,
- IEnumerable tags = null)
+ IEnumerable tags)
+ {
+ return AddAsyncCheck(builder, name, check, tags, default);
+ }
+
+ ///
+ /// Adds a new health check with the specified name and implementation.
+ ///
+ /// The .
+ /// The name of the health check.
+ /// A list of tags that can be used to filter health checks.
+ /// A delegate that provides the health check implementation.
+ /// An optional representing the timeout of the check.
+ /// The .
+ public static IHealthChecksBuilder AddAsyncCheck(
+ this IHealthChecksBuilder builder,
+ string name,
+ Func> check,
+ IEnumerable tags = null,
+ TimeSpan? timeout = default)
{
if (builder == null)
{
@@ -143,7 +223,7 @@ namespace Microsoft.Extensions.DependencyInjection
}
var instance = new DelegateHealthCheck((ct) => check(ct));
- return builder.Add(new HealthCheckRegistration(name, instance, failureStatus: null, tags));
+ return builder.Add(new HealthCheckRegistration(name, instance, failureStatus: null, tags, timeout));
}
}
}
diff --git a/src/HealthChecks/HealthChecks/src/HealthCheckPublisherOptions.cs b/src/HealthChecks/HealthChecks/src/HealthCheckPublisherOptions.cs
index 1313718af8..6b7c8c3365 100644
--- a/src/HealthChecks/HealthChecks/src/HealthCheckPublisherOptions.cs
+++ b/src/HealthChecks/HealthChecks/src/HealthCheckPublisherOptions.cs
@@ -60,7 +60,7 @@ namespace Microsoft.Extensions.Diagnostics.HealthChecks
throw new ArgumentException($"The {nameof(Period)} must not be infinite.", nameof(value));
}
- _delay = value;
+ _period = value;
}
}
diff --git a/src/HealthChecks/HealthChecks/src/Microsoft.Extensions.Diagnostics.HealthChecks.csproj b/src/HealthChecks/HealthChecks/src/Microsoft.Extensions.Diagnostics.HealthChecks.csproj
index d0b1c97ef0..463e5b3632 100644
--- a/src/HealthChecks/HealthChecks/src/Microsoft.Extensions.Diagnostics.HealthChecks.csproj
+++ b/src/HealthChecks/HealthChecks/src/Microsoft.Extensions.Diagnostics.HealthChecks.csproj
@@ -10,8 +10,13 @@ Microsoft.Extensions.Diagnostics.HealthChecks.IHealthChecksBuilder
$(NoWarn);CS1591
true
diagnostics;healthchecks
+ true
+
+
+
+
diff --git a/src/HealthChecks/HealthChecks/src/Properties/AssemblyInfo.cs b/src/HealthChecks/HealthChecks/src/Properties/AssemblyInfo.cs
deleted file mode 100644
index 13e969bfad..0000000000
--- a/src/HealthChecks/HealthChecks/src/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,3 +0,0 @@
-using System.Runtime.CompilerServices;
-
-[assembly: InternalsVisibleTo("Microsoft.Extensions.Diagnostics.HealthChecks.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
\ No newline at end of file
diff --git a/src/HealthChecks/HealthChecks/src/baseline.netcore.json b/src/HealthChecks/HealthChecks/src/baseline.netcore.json
deleted file mode 100644
index cb2fe053f1..0000000000
--- a/src/HealthChecks/HealthChecks/src/baseline.netcore.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "AssemblyIdentity": "Microsoft.Extensions.Diagnostics.HealthChecks, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60",
- "Types": [
- ]
-}
\ No newline at end of file
diff --git a/src/HealthChecks/HealthChecks/test/DefaultHealthCheckServiceTest.cs b/src/HealthChecks/HealthChecks/test/DefaultHealthCheckServiceTest.cs
index 9ab991204e..ba0a2f32d5 100644
--- a/src/HealthChecks/HealthChecks/test/DefaultHealthCheckServiceTest.cs
+++ b/src/HealthChecks/HealthChecks/test/DefaultHealthCheckServiceTest.cs
@@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using Microsoft.AspNetCore.Testing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Testing;
@@ -375,6 +376,80 @@ namespace Microsoft.Extensions.Diagnostics.HealthChecks
});
}
+ [Fact]
+ public async Task CheckHealthAsync_ChecksAreRunInParallel()
+ {
+ // Arrange
+ var input1 = new TaskCompletionSource