Skip to content

Commit cd457d0

Browse files
committed
Refactor : Introduce AssemblyFinder
to avoid checks for null dependencyContext in ConfigurationReader and split responsabilities
1 parent 901f7c1 commit cd457d0

11 files changed

+145
-83
lines changed

src/Serilog.Settings.Configuration/ConfigurationLoggerConfigurationExtensions.cs

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
using Microsoft.Extensions.DependencyModel;
1818
using Serilog.Configuration;
1919
using Serilog.Settings.Configuration;
20-
using System.Reflection;
20+
using Serilog.Settings.Configuration.Assemblies;
2121

2222
namespace Serilog
2323
{
@@ -48,10 +48,15 @@ public static LoggerConfiguration Configuration(
4848
{
4949
if (configuration == null) throw new ArgumentNullException(nameof(configuration));
5050

51+
var assemblyFinder = dependencyContext == null
52+
? AssemblyFinder.Auto()
53+
: AssemblyFinder.ForDependencyContext(dependencyContext);
54+
5155
return settingConfiguration.Settings(
5256
new ConfigurationReader(
53-
configuration,
54-
dependencyContext ?? (Assembly.GetEntryAssembly() != null ? DependencyContext.Default : null)));
57+
configuration.GetSection(DefaultSectionName),
58+
assemblyFinder,
59+
configuration));
5560
}
5661

5762
/// <summary>
@@ -71,10 +76,15 @@ public static LoggerConfiguration ConfigurationSection(
7176
if (settingConfiguration == null) throw new ArgumentNullException(nameof(settingConfiguration));
7277
if (configSection == null) throw new ArgumentNullException(nameof(configSection));
7378

79+
var assemblyFinder = dependencyContext == null
80+
? AssemblyFinder.Auto()
81+
: AssemblyFinder.ForDependencyContext(dependencyContext);
82+
7483
return settingConfiguration.Settings(
7584
new ConfigurationReader(
7685
configSection,
77-
dependencyContext ?? (Assembly.GetEntryAssembly() != null ? DependencyContext.Default : null)));
86+
assemblyFinder,
87+
configuration: null));
7888
}
7989

8090
/// <summary>
@@ -93,14 +103,9 @@ public static LoggerConfiguration Configuration(
93103
{
94104
if (configuration == null) throw new ArgumentNullException(nameof(configuration));
95105

96-
if(configurationAssemblySource == ConfigurationAssemblySource.UseLoadedAssemblies)
97-
{
98-
return Configuration(settingConfiguration, configuration);
99-
}
100-
else
101-
{
102-
return settingConfiguration.Settings(new ConfigurationReader(configuration, null));
103-
}
106+
var assemblyFinder = AssemblyFinder.ForSource(configurationAssemblySource);
107+
108+
return settingConfiguration.Settings(new ConfigurationReader(configuration.GetSection(DefaultSectionName), assemblyFinder, configuration));
104109
}
105110

106111
/// <summary>
@@ -119,14 +124,9 @@ public static LoggerConfiguration ConfigurationSection(
119124
if (settingConfiguration == null) throw new ArgumentNullException(nameof(settingConfiguration));
120125
if (configSection == null) throw new ArgumentNullException(nameof(configSection));
121126

122-
if (configurationAssemblySource == ConfigurationAssemblySource.UseLoadedAssemblies)
123-
{
124-
return Configuration(settingConfiguration, configSection);
125-
}
126-
else
127-
{
128-
return settingConfiguration.Settings(new ConfigurationReader(configSection, null));
129-
}
127+
var assemblyFinder = AssemblyFinder.ForSource(configurationAssemblySource);
128+
129+
return settingConfiguration.Settings(new ConfigurationReader(configSection, assemblyFinder, configuration: null));
130130
}
131131
}
132132
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Reflection;
4+
using Microsoft.Extensions.DependencyModel;
5+
6+
namespace Serilog.Settings.Configuration.Assemblies
7+
{
8+
abstract class AssemblyFinder
9+
{
10+
public abstract IReadOnlyList<AssemblyName> FindAssembliesContainingName(string nameToFind);
11+
12+
protected static bool IsCaseInsensitiveMatch(string text, string textToFind)
13+
{
14+
return text != null && text.ToLowerInvariant().Contains(textToFind.ToLowerInvariant());
15+
}
16+
17+
public static AssemblyFinder Auto()
18+
{
19+
if (Assembly.GetEntryAssembly() != null)
20+
{
21+
return new DependencyContextAssemblyFinder(DependencyContext.Default);
22+
}
23+
return new DllScanningAssemblyFinder();
24+
}
25+
26+
public static AssemblyFinder ForSource(ConfigurationAssemblySource configurationAssemblySource)
27+
{
28+
switch (configurationAssemblySource)
29+
{
30+
case ConfigurationAssemblySource.UseLoadedAssemblies:
31+
return Auto();
32+
case ConfigurationAssemblySource.AlwaysScanDllFiles:
33+
return new DllScanningAssemblyFinder();
34+
default:
35+
throw new ArgumentOutOfRangeException(nameof(configurationAssemblySource), configurationAssemblySource, null);
36+
}
37+
}
38+
39+
public static AssemblyFinder ForDependencyContext(DependencyContext dependencyContext)
40+
{
41+
return new DependencyContextAssemblyFinder(dependencyContext);
42+
}
43+
}
44+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Reflection;
5+
using Microsoft.Extensions.DependencyModel;
6+
7+
namespace Serilog.Settings.Configuration.Assemblies
8+
{
9+
sealed class DependencyContextAssemblyFinder : AssemblyFinder
10+
{
11+
readonly DependencyContext _dependencyContext;
12+
13+
public DependencyContextAssemblyFinder(DependencyContext dependencyContext)
14+
{
15+
_dependencyContext = dependencyContext ?? throw new ArgumentNullException(nameof(dependencyContext));
16+
}
17+
18+
public override IReadOnlyList<AssemblyName> FindAssembliesContainingName(string nameToFind)
19+
{
20+
var query = from library in _dependencyContext.RuntimeLibraries
21+
from assemblyName in library.GetDefaultAssemblyNames(_dependencyContext)
22+
where IsCaseInsensitiveMatch(assemblyName.Name, nameToFind)
23+
select assemblyName;
24+
25+
return query.ToList().AsReadOnly();
26+
}
27+
}
28+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Reflection;
5+
6+
namespace Serilog.Settings.Configuration.Assemblies
7+
{
8+
sealed class DllScanningAssemblyFinder : AssemblyFinder
9+
{
10+
public override IReadOnlyList<AssemblyName> FindAssembliesContainingName(string nameToFind)
11+
{
12+
var query = from outputAssemblyPath in System.IO.Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory, "*.dll")
13+
let assemblyFileName = System.IO.Path.GetFileNameWithoutExtension(outputAssemblyPath)
14+
where IsCaseInsensitiveMatch(assemblyFileName, nameToFind)
15+
select AssemblyName.GetAssemblyName(outputAssemblyPath);
16+
17+
return query.ToList().AsReadOnly();
18+
}
19+
}
20+
}

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

Lines changed: 13 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@
44
using System.Reflection;
55
using System.Runtime.CompilerServices;
66
using Microsoft.Extensions.Configuration;
7-
using Microsoft.Extensions.DependencyModel;
87
using Microsoft.Extensions.Primitives;
8+
using System.Text.RegularExpressions;
99

1010
using Serilog.Configuration;
1111
using Serilog.Core;
1212
using Serilog.Debugging;
1313
using Serilog.Events;
14-
using System.Text.RegularExpressions;
14+
using Serilog.Settings.Configuration.Assemblies;
1515

1616
namespace Serilog.Settings.Configuration
1717
{
@@ -22,32 +22,23 @@ class ConfigurationReader : IConfigurationReader
2222
readonly IConfiguration _configuration;
2323

2424
readonly IConfigurationSection _section;
25-
readonly DependencyContext _dependencyContext;
25+
readonly AssemblyFinder _assemblyFinder;
2626
readonly IReadOnlyCollection<Assembly> _configurationAssemblies;
2727

28-
public ConfigurationReader(IConfiguration configuration, DependencyContext dependencyContext)
29-
{
30-
_configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
31-
_section = configuration.GetSection(ConfigurationLoggerConfigurationExtensions.DefaultSectionName);
32-
_dependencyContext = dependencyContext;
33-
_configurationAssemblies = LoadConfigurationAssemblies();
34-
}
35-
36-
// Generally the initial call should use IConfiguration rather than IConfigurationSection, otherwise
37-
// IConfiguration parameters in the target methods will not be populated.
38-
public ConfigurationReader(IConfigurationSection configSection, DependencyContext dependencyContext)
28+
public ConfigurationReader(IConfigurationSection configSection, AssemblyFinder assemblyFinder, IConfiguration configuration = null)
3929
{
4030
_section = configSection ?? throw new ArgumentNullException(nameof(configSection));
41-
_dependencyContext = dependencyContext;
42-
_configurationAssemblies = LoadConfigurationAssemblies();
31+
_assemblyFinder = assemblyFinder ?? throw new ArgumentNullException(nameof(assemblyFinder));
32+
_configuration = configuration;
33+
_configurationAssemblies = LoadConfigurationAssemblies(_section, _assemblyFinder);
4334
}
4435

4536
// Used internally for processing nested configuration sections -- see GetMethodCalls below.
46-
internal ConfigurationReader(IConfigurationSection configSection, IReadOnlyCollection<Assembly> configurationAssemblies, DependencyContext dependencyContext, SettingValueResolver valueResolver)
37+
internal ConfigurationReader(IConfigurationSection configSection, IReadOnlyCollection<Assembly> configurationAssemblies, AssemblyFinder assemblyFinder, SettingValueResolver valueResolver)
4738
{
4839
_section = configSection ?? throw new ArgumentNullException(nameof(configSection));
49-
_dependencyContext = dependencyContext;
5040
_configurationAssemblies = configurationAssemblies ?? throw new ArgumentNullException(nameof(configurationAssemblies));
41+
_assemblyFinder = assemblyFinder ?? throw new ArgumentNullException(nameof(assemblyFinder));
5142
_configuration = valueResolver.AppConfiguration;
5243
}
5344

@@ -252,7 +243,7 @@ IConfigurationArgumentValue GetArgumentValue(IConfigurationSection argumentSecti
252243
}
253244
else
254245
{
255-
argumentValue = new ObjectArgumentValue(argumentSection, _configurationAssemblies, _dependencyContext);
246+
argumentValue = new ObjectArgumentValue(argumentSection, _configurationAssemblies, _assemblyFinder);
256247
}
257248

258249
return argumentValue;
@@ -268,11 +259,11 @@ string GetSectionName(IConfigurationSection s)
268259
}
269260
}
270261

271-
IReadOnlyCollection<Assembly> LoadConfigurationAssemblies()
262+
static IReadOnlyCollection<Assembly> LoadConfigurationAssemblies(IConfigurationSection section, AssemblyFinder assemblyFinder)
272263
{
273264
var assemblies = new Dictionary<string, Assembly>();
274265

275-
var usingSection = _section.GetSection("Using");
266+
var usingSection = section.GetSection("Using");
276267
if (usingSection.GetChildren().Any())
277268
{
278269
foreach (var simpleName in usingSection.GetChildren().Select(c => c.Value))
@@ -287,7 +278,7 @@ IReadOnlyCollection<Assembly> LoadConfigurationAssemblies()
287278
}
288279
}
289280

290-
foreach (var assemblyName in GetSerilogConfigurationAssemblies())
281+
foreach (var assemblyName in assemblyFinder.FindAssembliesContainingName("serilog"))
291282
{
292283
var assumed = Assembly.Load(assemblyName);
293284
if (assumed != null && !assemblies.ContainsKey(assumed.FullName))
@@ -297,30 +288,6 @@ IReadOnlyCollection<Assembly> LoadConfigurationAssemblies()
297288
return assemblies.Values.ToList().AsReadOnly();
298289
}
299290

300-
AssemblyName[] GetSerilogConfigurationAssemblies()
301-
{
302-
// ReSharper disable once RedundantAssignment
303-
var query = Enumerable.Empty<AssemblyName>();
304-
var filter = new Func<string, bool>(name => name != null && name.ToLowerInvariant().Contains("serilog"));
305-
306-
if (_dependencyContext != null)
307-
{
308-
query = from library in _dependencyContext.RuntimeLibraries
309-
from assemblyName in library.GetDefaultAssemblyNames(_dependencyContext)
310-
where filter(assemblyName.Name)
311-
select assemblyName;
312-
}
313-
else
314-
{
315-
query = from outputAssemblyPath in System.IO.Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory, "*.dll")
316-
let assemblyFileName = System.IO.Path.GetFileNameWithoutExtension(outputAssemblyPath)
317-
where filter(assemblyFileName)
318-
select AssemblyName.GetAssemblyName(outputAssemblyPath);
319-
}
320-
321-
return query.ToArray();
322-
}
323-
324291
static void CallConfigurationMethods(ILookup<string, Dictionary<string, IConfigurationArgumentValue>> methods, IList<MethodInfo> configurationMethods, object receiver, SettingValueResolver valueResolver)
325292
{
326293
foreach (var method in methods.SelectMany(g => g.Select(x => new { g.Key, Value = x })))
Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,32 @@
11
using Microsoft.Extensions.Configuration;
2-
using Microsoft.Extensions.DependencyModel;
3-
using Serilog.Configuration;
42
using System;
53
using System.Collections.Generic;
64
using System.Reflection;
75

6+
using Serilog.Configuration;
7+
using Serilog.Settings.Configuration.Assemblies;
8+
89
namespace Serilog.Settings.Configuration
910
{
1011
class ObjectArgumentValue : IConfigurationArgumentValue
1112
{
12-
readonly IConfigurationSection section;
13-
readonly IReadOnlyCollection<Assembly> configurationAssemblies;
14-
readonly DependencyContext dependencyContext;
13+
readonly IConfigurationSection _section;
14+
readonly IReadOnlyCollection<Assembly> _configurationAssemblies;
15+
readonly AssemblyFinder _assemblyFinder;
1516

16-
public ObjectArgumentValue(IConfigurationSection section, IReadOnlyCollection<Assembly> configurationAssemblies, DependencyContext dependencyContext)
17+
public ObjectArgumentValue(IConfigurationSection section, IReadOnlyCollection<Assembly> configurationAssemblies, AssemblyFinder assemblyFinder)
1718
{
18-
this.section = section;
19+
_section = section ?? throw new ArgumentNullException(nameof(section));
1920

2021
// used by nested logger configurations to feed a new pass by ConfigurationReader
21-
this.configurationAssemblies = configurationAssemblies;
22-
this.dependencyContext = dependencyContext;
22+
_configurationAssemblies = configurationAssemblies ?? throw new ArgumentNullException(nameof(configurationAssemblies));
23+
_assemblyFinder = assemblyFinder ?? throw new ArgumentNullException(nameof(assemblyFinder));
2324
}
2425

2526
public object ConvertTo(Type toType, SettingValueResolver valueResolver)
2627
{
2728
// return the entire section for internal processing
28-
if (toType == typeof(IConfigurationSection)) return section;
29+
if (toType == typeof(IConfigurationSection)) return _section;
2930

3031
// process a nested configuration to populate an Action<> logger/sink config parameter?
3132
var typeInfo = toType.GetTypeInfo();
@@ -36,7 +37,7 @@ public object ConvertTo(Type toType, SettingValueResolver valueResolver)
3637
if (configType != typeof(LoggerConfiguration) && configType != typeof(LoggerSinkConfiguration))
3738
throw new ArgumentException($"Configuration for Action<{configType}> is not implemented.");
3839

39-
IConfigurationReader configReader = new ConfigurationReader(section, configurationAssemblies, dependencyContext, valueResolver);
40+
IConfigurationReader configReader = new ConfigurationReader(_section, _configurationAssemblies, _assemblyFinder, valueResolver);
4041

4142
if (configType == typeof(LoggerConfiguration))
4243
{
@@ -50,7 +51,7 @@ public object ConvertTo(Type toType, SettingValueResolver valueResolver)
5051
}
5152

5253
// MS Config binding
53-
return section.Get(toType);
54+
return _section.Get(toType);
5455
}
5556
}
5657
}

src/Serilog.Settings.Configuration/Settings/Configuration/SettingValueResolver.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-

2-
3-
using System;
1+
using System;
42
using System.Collections.Generic;
53
using Microsoft.Extensions.Configuration;
4+
65
using Serilog.Core;
76

87
namespace Serilog.Settings.Configuration

src/Serilog.Settings.Configuration/Settings/Configuration/StringArgumentValue.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
using System.Linq;
44
using System.Reflection;
55
using System.Text.RegularExpressions;
6-
using Microsoft.Extensions.Configuration;
76
using Microsoft.Extensions.Primitives;
87

98
using Serilog.Core;

src/Serilog.Settings.Configuration/Settings/Configuration/SurrogateConfigurationMethods.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.Generic;
33
using System.Linq;
44
using System.Reflection;
5+
56
using Serilog.Configuration;
67
using Serilog.Core;
78
using Serilog.Events;

0 commit comments

Comments
 (0)