Skip to content

Commit 140e365

Browse files
committed
Make sure that single-file apps can find assemblies that contains sinks
Before this commit, when single-file app was detected, the behaviour was to fallback on DLL scanning. But DLL scanning would not find anything for an app published as a single-file, by sheer definition of single-file app! After this commit, an exception is thrown if the app is published as a single-file AND no `Serilog:Using` section is defined in the configuration. The error message explains that either a `Serilog:Using` section must be added or show how to explicitly configure assemblies through the `ConfigurationReaderOptions`.
1 parent de58300 commit 140e365

File tree

5 files changed

+46
-21
lines changed

5 files changed

+46
-21
lines changed

src/Serilog.Settings.Configuration/Settings/Configuration/Assemblies/AssemblyFinder.cs

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,7 @@ protected static bool IsCaseInsensitiveMatch(string? text, string textToFind)
1414

1515
public static AssemblyFinder Auto()
1616
{
17-
try
18-
{
19-
// Need to check `Assembly.GetEntryAssembly()` first because
20-
// `DependencyContext.Default` throws an exception when `Assembly.GetEntryAssembly()` returns null
21-
if (Assembly.GetEntryAssembly() != null && DependencyContext.Default != null)
22-
{
23-
return new DependencyContextAssemblyFinder(DependencyContext.Default);
24-
}
25-
}
26-
catch (NotSupportedException) when (typeof(object).Assembly.Location is "") // bundled mode detection
27-
{
28-
}
29-
30-
return new DllScanningAssemblyFinder();
17+
return new AutoAssemblyFinder(new DependencyContextAssemblyFinder(DependencyContext.Default), new DllScanningAssemblyFinder());
3118
}
3219

3320
public static AssemblyFinder ForSource(ConfigurationAssemblySource configurationAssemblySource)
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
using System.Reflection;
2+
3+
namespace Serilog.Settings.Configuration.Assemblies;
4+
5+
class AutoAssemblyFinder : AssemblyFinder
6+
{
7+
readonly AssemblyFinder[] _assemblyFinders;
8+
9+
public AutoAssemblyFinder(params AssemblyFinder[] assemblyFinders)
10+
{
11+
_assemblyFinders = assemblyFinders;
12+
}
13+
14+
public override IReadOnlyList<AssemblyName> FindAssembliesContainingName(string nameToFind)
15+
{
16+
var assemblyNames = new List<AssemblyName>();
17+
foreach (var assemblyFinder in _assemblyFinders)
18+
{
19+
assemblyNames.AddRange(assemblyFinder.FindAssembliesContainingName(nameToFind));
20+
}
21+
return assemblyNames;
22+
}
23+
}

src/Serilog.Settings.Configuration/Settings/Configuration/Assemblies/DependencyContextAssemblyFinder.cs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,25 @@ namespace Serilog.Settings.Configuration.Assemblies;
55

66
sealed class DependencyContextAssemblyFinder : AssemblyFinder
77
{
8-
readonly DependencyContext _dependencyContext;
8+
readonly DependencyContext? _dependencyContext;
99

10-
public DependencyContextAssemblyFinder(DependencyContext dependencyContext)
10+
public DependencyContextAssemblyFinder(DependencyContext? dependencyContext)
1111
{
12-
_dependencyContext = dependencyContext ?? throw new ArgumentNullException(nameof(dependencyContext));
12+
_dependencyContext = dependencyContext;
1313
}
1414

1515
public override IReadOnlyList<AssemblyName> FindAssembliesContainingName(string nameToFind)
1616
{
17+
if (_dependencyContext == null)
18+
return Array.Empty<AssemblyName>();
19+
1720
var query = from library in _dependencyContext.RuntimeLibraries
1821
where IsReferencingSerilog(library)
1922
from assemblyName in library.GetDefaultAssemblyNames(_dependencyContext)
2023
where IsCaseInsensitiveMatch(assemblyName.Name, nameToFind)
2124
select assemblyName;
2225

23-
return query.ToList().AsReadOnly();
26+
return query.ToList();
2427

2528
static bool IsReferencingSerilog(Library library)
2629
{

src/Serilog.Settings.Configuration/Settings/Configuration/Assemblies/DllScanningAssemblyFinder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ where IsCaseInsensitiveMatch(assemblyFileName, nameToFind)
4444
where assemblyName != null
4545
select assemblyName;
4646

47-
return query.ToList().AsReadOnly();
47+
return query.ToList();
4848

4949
static AssemblyName? TryGetAssemblyNameFrom(string path)
5050
{

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

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,7 @@ static IReadOnlyCollection<Assembly> LoadConfigurationAssemblies(IConfiguration
368368
{
369369
if (string.IsNullOrWhiteSpace(simpleName))
370370
throw new InvalidOperationException(
371-
"A zero-length or whitespace assembly name was supplied to a Serilog.Using configuration statement.");
371+
$"A zero-length or whitespace assembly name was supplied to a {usingSection.Path} configuration statement.");
372372

373373
var assembly = Assembly.Load(new AssemblyName(simpleName));
374374
if (!assemblies.ContainsKey(assembly.FullName))
@@ -383,7 +383,19 @@ static IReadOnlyCollection<Assembly> LoadConfigurationAssemblies(IConfiguration
383383
assemblies.Add(assumed.FullName, assumed);
384384
}
385385

386-
return assemblies.Values.ToList().AsReadOnly();
386+
if (assemblies.Count == 1)
387+
{
388+
var message = $"""
389+
No {usingSection.Path} configuration section is defined and no Serilog assemblies were found.
390+
This is most likely because the application is published as single-file.
391+
Either add a {usingSection.Path} section or explicitly specify assemblies that contains sinks and other types through the reader options. For example:
392+
var options = new ConfigurationReaderOptions(typeof(ConsoleLoggerConfigurationExtensions).Assembly, typeof(SerilogExpression).Assembly);
393+
new LoggerConfiguration().ReadFrom.Configuration(configuration, options);
394+
""";
395+
throw new InvalidOperationException(message);
396+
}
397+
398+
return assemblies.Values;
387399
}
388400

389401
void CallConfigurationMethods(ILookup<string, Dictionary<string, IConfigurationArgumentValue>> methods, IReadOnlyCollection<MethodInfo> configurationMethods, object receiver)

0 commit comments

Comments
 (0)