Skip to content

Commit e9dfb98

Browse files
authored
Merge pull request #105 from MV10/multiple-value-exception
Multiple value exception, fixes #103
2 parents 62acc84 + 67e7ca8 commit e9dfb98

File tree

2 files changed

+60
-9
lines changed

2 files changed

+60
-9
lines changed

src/Serilog.Settings.Configuration/Settings/Configuration/ConfigurationReader.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,16 @@ internal ILookup<string, Dictionary<string, IConfigurationArgumentValue>> GetMet
221221
IConfigurationArgumentValue GetArgumentValue(IConfigurationSection argumentSection)
222222
{
223223
IConfigurationArgumentValue argumentValue;
224+
225+
// Reject configurations where an element has both scalar and complex
226+
// values as a result of reading multiple configuration sources.
227+
if (argumentSection.Value != null && argumentSection.GetChildren().Any())
228+
throw new InvalidOperationException(
229+
$"The value for the argument '{argumentSection.Path}' is assigned different value " +
230+
"types in more than one configuration source. Ensure all configurations consistently " +
231+
"use either a scalar (int, string, boolean) or a complex (array, section, list, " +
232+
"POCO, etc.) type for this argument value.");
233+
224234
if (argumentSection.Value != null)
225235
{
226236
argumentValue = new StringArgumentValue(() => argumentSection.Value, argumentSection.GetReloadToken);

test/Serilog.Settings.Configuration.Tests/ConfigurationSettingsTests.cs

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,12 @@ namespace Serilog.Settings.Configuration.Tests
1212
{
1313
public class ConfigurationSettingsTests
1414
{
15-
static LoggerConfiguration ConfigFromJson(string jsonString)
15+
static LoggerConfiguration ConfigFromJson(string jsonString, string secondJsonSource = null)
1616
{
17-
var config = new ConfigurationBuilder().AddJsonString(jsonString).Build();
17+
var builder = new ConfigurationBuilder().AddJsonString(jsonString);
18+
if (secondJsonSource != null)
19+
builder.AddJsonString(secondJsonSource);
20+
var config = builder.Build();
1821
return new LoggerConfiguration()
1922
.ReadFrom.Configuration(config);
2023
}
@@ -31,7 +34,7 @@ public void PropertyEnrichmentIsApplied()
3134
}
3235
}
3336
}";
34-
37+
3538
var log = ConfigFromJson(json)
3639
.WriteTo.Sink(new DelegatingSink(e => evt = e))
3740
.CreateLogger();
@@ -114,7 +117,7 @@ public void AuditSinksAreConfigured()
114117

115118
var log = ConfigFromJson(json)
116119
.CreateLogger();
117-
120+
118121
DummyRollingFileSink.Emitted.Clear();
119122
DummyRollingFileAuditSink.Emitted.Clear();
120123

@@ -227,7 +230,7 @@ public void LoggingLevelSwitchWithInvalidNameThrowsFormatException()
227230
""LevelSwitches"": {""switchNameNotStartingWithDollar"" : ""Warning"" }
228231
}
229232
}";
230-
233+
231234
var ex = Assert.Throws<FormatException>(() => ConfigFromJson(json));
232235

233236
Assert.Contains("\"switchNameNotStartingWithDollar\"", ex.Message);
@@ -271,7 +274,7 @@ public void SettingMinimumLevelControlledByToAnUndeclaredSwitchThrows()
271274
}
272275
}
273276
}";
274-
277+
275278
var ex = Assert.Throws<InvalidOperationException>(() =>
276279
ConfigFromJson(json)
277280
.CreateLogger());
@@ -332,7 +335,7 @@ public void ReferencingAnUndeclaredSwitchInSinkThrows()
332335
}]
333336
}
334337
}";
335-
338+
336339
var ex = Assert.Throws<InvalidOperationException>(() =>
337340
ConfigFromJson(json)
338341
.CreateLogger());
@@ -544,8 +547,8 @@ public void WriteToSubLoggerWithLevelSwitchIsSupported()
544547
}
545548
}]
546549
}
547-
}";
548-
550+
}";
551+
549552
var log = ConfigFromJson(json)
550553
.CreateLogger();
551554

@@ -556,5 +559,43 @@ public void WriteToSubLoggerWithLevelSwitchIsSupported()
556559

557560
Assert.Equal(1, DummyRollingFileSink.Emitted.Count);
558561
}
562+
563+
[Trait("Bugfix", "#103")]
564+
[Fact]
565+
public void InconsistentComplexVsScalarArgumentValuesThrowsIOE()
566+
{
567+
var jsonDiscreteValue = @"{
568+
""Serilog"": {
569+
""Using"": [""TestDummies""],
570+
""WriteTo"": [{
571+
""Name"": ""DummyRollingFile"",
572+
""Args"": {""pathFormat"" : ""C:\\""}
573+
}]
574+
}
575+
}";
576+
577+
var jsonComplexValue = @"{
578+
""Serilog"": {
579+
""Using"": [""TestDummies""],
580+
""WriteTo"": [{
581+
""Name"": ""DummyRollingFile"",
582+
""Args"": {""pathFormat"" : { ""foo"" : ""bar"" } }
583+
}]
584+
}
585+
}";
586+
587+
// These will combine into a ConfigurationSection object that has both
588+
// Value == "C:\" and GetChildren() == List<string>. No configuration
589+
// extension matching this exists (in theory an "object" argument could
590+
// accept either value). ConfigurationReader should throw as soon as
591+
// the multiple values are recognized; it will never attempt to locate
592+
// a matching argument.
593+
594+
var ex = Assert.Throws<InvalidOperationException>(()
595+
=> ConfigFromJson(jsonDiscreteValue, jsonComplexValue));
596+
597+
Assert.Contains("The value for the argument", ex.Message);
598+
Assert.Contains("'Serilog:WriteTo:0:Args:pathFormat'", ex.Message);
599+
}
559600
}
560601
}

0 commit comments

Comments
 (0)