1
- using System ;
1
+ using System ;
2
2
using System . Collections . Generic ;
3
3
using System . Linq ;
4
4
using System . Reflection ;
@@ -325,50 +325,66 @@ static void CallConfigurationMethods(ILookup<string, Dictionary<string, IConfigu
325
325
{
326
326
foreach ( var method in methods . SelectMany ( g => g . Select ( x => new { g . Key , Value = x } ) ) )
327
327
{
328
- var methodInfo = SelectConfigurationMethod ( configurationMethods , method . Key , method . Value ) ;
328
+ var methodInfo = SelectConfigurationMethod ( configurationMethods , method . Key , method . Value . Keys ) ;
329
329
330
330
if ( methodInfo != null )
331
331
{
332
332
var call = ( from p in methodInfo . GetParameters ( ) . Skip ( 1 )
333
- let directive = method . Value . FirstOrDefault ( s => s . Key . Equals ( p . Name , StringComparison . OrdinalIgnoreCase ) )
333
+ let directive = method . Value . FirstOrDefault ( s => ParameterNameMatches ( p . Name , s . Key ) )
334
334
select directive . Key == null
335
- ? p . DefaultValue
335
+ ? GetImplicitValueForNotSpecifiedKey ( p , valueResolver , methodInfo )
336
336
: directive . Value . ConvertTo ( p . ParameterType , valueResolver ) ) . ToList ( ) ;
337
337
338
- var parm = methodInfo . GetParameters ( ) . FirstOrDefault ( i => i . ParameterType == typeof ( IConfiguration ) ) ;
339
- if ( parm != null && ! parm . HasDefaultValue )
340
- {
341
- if ( valueResolver . AppConfiguration is null )
342
- {
343
- throw new InvalidOperationException ( "Trying to invoke a configuration method accepting a `IConfiguration` argument. " +
344
- $ "This is not supported when only a `IConfigSection` has been provided. (method '{ methodInfo } ')") ;
345
- }
346
- call [ parm . Position - 1 ] = valueResolver . AppConfiguration ;
347
- }
348
-
349
338
call . Insert ( 0 , receiver ) ;
350
-
351
339
methodInfo . Invoke ( null , call . ToArray ( ) ) ;
352
340
}
353
341
}
354
342
}
355
343
356
- internal static MethodInfo SelectConfigurationMethod ( IEnumerable < MethodInfo > candidateMethods , string name , Dictionary < string , IConfigurationArgumentValue > suppliedArgumentValues )
344
+ static bool HasImplicitValueWhenNotSpecified ( ParameterInfo paramInfo )
345
+ {
346
+ return paramInfo . HasDefaultValue
347
+ // parameters of type IConfiguration are implicitly populated with provided Configuration
348
+ || paramInfo . ParameterType == typeof ( IConfiguration ) ;
349
+ }
350
+
351
+ static object GetImplicitValueForNotSpecifiedKey ( ParameterInfo parameter , SettingValueResolver valueResolver , MethodInfo methodToInvoke )
352
+ {
353
+ if ( ! HasImplicitValueWhenNotSpecified ( parameter ) )
354
+ {
355
+ throw new InvalidOperationException ( "GetImplicitValueForNotSpecifiedKey() should only be called for parameters for which HasImplicitValueWhenNotSpecified() is true. " +
356
+ "This means something is wrong in the Serilog.Settings.Configuration code." ) ;
357
+ }
358
+
359
+ if ( parameter . ParameterType == typeof ( IConfiguration ) )
360
+ {
361
+ if ( parameter . HasDefaultValue )
362
+ {
363
+ return valueResolver . AppConfiguration ?? parameter . DefaultValue ;
364
+ }
365
+
366
+ return valueResolver . AppConfiguration
367
+ ?? throw new InvalidOperationException ( "Trying to invoke a configuration method accepting a `IConfiguration` argument. " +
368
+ $ "This is not supported when only a `IConfigSection` has been provided. (method '{ methodToInvoke } ')") ;
369
+ }
370
+
371
+ return parameter . DefaultValue ;
372
+ }
373
+
374
+ internal static MethodInfo SelectConfigurationMethod ( IEnumerable < MethodInfo > candidateMethods , string name , IEnumerable < string > suppliedArgumentNames )
357
375
{
358
376
// Per issue #111, it is safe to use case-insensitive matching on argument names. The CLR doesn't permit this type
359
377
// of overloading, and the Microsoft.Extensions.Configuration keys are case-insensitive (case is preserved with some
360
378
// config sources, but key-matching is case-insensitive and case-preservation does not appear to be guaranteed).
361
379
return candidateMethods
362
- . Where ( m => m . Name == name &&
363
- m . GetParameters ( ) . Skip ( 1 )
364
- . All ( p => p . HasDefaultValue
365
- || suppliedArgumentValues . Any ( s => s . Key . Equals ( p . Name , StringComparison . OrdinalIgnoreCase ) )
366
- // parameters of type IConfiguration are implicitly populated with provided Configuration
367
- || p . ParameterType == typeof ( IConfiguration )
368
- ) )
380
+ . Where ( m => m . Name == name )
381
+ . Where ( m => m . GetParameters ( )
382
+ . Skip ( 1 )
383
+ . All ( p => HasImplicitValueWhenNotSpecified ( p ) ||
384
+ ParameterNameMatches ( p . Name , suppliedArgumentNames ) ) )
369
385
. OrderByDescending ( m =>
370
386
{
371
- var matchingArgs = m . GetParameters ( ) . Where ( p => suppliedArgumentValues . Any ( s => s . Key . Equals ( p . Name , StringComparison . OrdinalIgnoreCase ) ) ) . ToList ( ) ;
387
+ var matchingArgs = m . GetParameters ( ) . Where ( p => ParameterNameMatches ( p . Name , suppliedArgumentNames ) ) . ToList ( ) ;
372
388
373
389
// Prefer the configuration method with most number of matching arguments and of those the ones with
374
390
// the most string type parameters to predict best match with least type casting
@@ -379,6 +395,16 @@ internal static MethodInfo SelectConfigurationMethod(IEnumerable<MethodInfo> can
379
395
. FirstOrDefault ( ) ;
380
396
}
381
397
398
+ static bool ParameterNameMatches ( string actualParameterName , string suppliedName )
399
+ {
400
+ return suppliedName . Equals ( actualParameterName , StringComparison . OrdinalIgnoreCase ) ;
401
+ }
402
+
403
+ static bool ParameterNameMatches ( string actualParameterName , IEnumerable < string > suppliedNames )
404
+ {
405
+ return suppliedNames . Any ( s => ParameterNameMatches ( actualParameterName , s ) ) ;
406
+ }
407
+
382
408
static IList < MethodInfo > FindSinkConfigurationMethods ( IReadOnlyCollection < Assembly > configurationAssemblies )
383
409
{
384
410
var found = FindConfigurationExtensionMethods ( configurationAssemblies , typeof ( LoggerSinkConfiguration ) ) ;
0 commit comments