diff --git a/src/AutofacSerilogIntegration/ContextualLoggingModule.cs b/src/AutofacSerilogIntegration/ContextualLoggingModule.cs
index 4790117..72fd229 100644
--- a/src/AutofacSerilogIntegration/ContextualLoggingModule.cs
+++ b/src/AutofacSerilogIntegration/ContextualLoggingModule.cs
@@ -3,6 +3,7 @@
using System.Reflection;
using Autofac;
using Autofac.Core;
+using Autofac.Core.Activators.ProvidedInstance;
using Autofac.Core.Activators.Reflection;
using Autofac.Core.Registration;
using Serilog;
@@ -18,6 +19,7 @@ internal class ContextualLoggingModule : Module
readonly bool _autowireProperties;
readonly bool _skipRegistration;
readonly bool _dispose;
+ readonly bool _alwaysSupplyParameter;
[Obsolete("Do not use this constructor. This is required by the Autofac assembly scanning")]
public ContextualLoggingModule()
@@ -26,11 +28,12 @@ public ContextualLoggingModule()
_skipRegistration = true;
}
- internal ContextualLoggingModule(ILogger logger = null, bool autowireProperties = false, bool dispose = false)
+ internal ContextualLoggingModule(ILogger logger = null, bool autowireProperties = false, bool dispose = false, bool alwaysSupplyParameter = false)
{
_logger = logger;
_autowireProperties = autowireProperties;
_dispose = dispose;
+ _alwaysSupplyParameter = alwaysSupplyParameter;
_skipRegistration = false;
}
@@ -94,41 +97,51 @@ protected override void AttachToComponentRegistration(IComponentRegistryBuilder
PropertyInfo[] targetProperties = null;
- var ra = registration.Activator as ReflectionActivator;
- if (ra != null)
+ switch (registration.Activator)
{
- // As of Autofac v4.7.0 "FindConstructors" will throw "NoConstructorsFoundException" instead of returning an empty array
- // See: https://github.com/autofac/Autofac/pull/895 & https://github.com/autofac/Autofac/issues/733
- ConstructorInfo[] ctors;
- try
- {
- ctors = ra.ConstructorFinder.FindConstructors(ra.LimitType);
- }
- catch (Exception ex) when (ex.GetType().Name == "NoConstructorsFoundException") // Avoid needing to upgrade our Autofac reference to 4.7.0
- {
- ctors = new ConstructorInfo[0];
- }
-
- var usesLogger =
- ctors.SelectMany(ctor => ctor.GetParameters()).Any(pi => pi.ParameterType == typeof (ILogger));
+ case ReflectionActivator ra:
+ // As of Autofac v4.7.0 "FindConstructors" will throw "NoConstructorsFoundException" instead of returning an empty array
+ // See: https://github.com/autofac/Autofac/pull/895 & https://github.com/autofac/Autofac/issues/733
+ ConstructorInfo[] ctors;
+ try
+ {
+ ctors = ra.ConstructorFinder.FindConstructors(ra.LimitType);
+ }
+ catch (NoConstructorsFoundException)
+ {
+ ctors = new ConstructorInfo[0];
+ }
- if (_autowireProperties)
- {
- var logProperties = ra.LimitType
- .GetRuntimeProperties()
- .Where(c => c.CanWrite && c.PropertyType == typeof(ILogger) && c.SetMethod.IsPublic && !c.SetMethod.IsStatic)
- .ToArray();
+ var usesLogger =
+ ctors.SelectMany(ctor => ctor.GetParameters()).Any(pi => pi.ParameterType == typeof(ILogger));
- if (logProperties.Any())
+ if (_autowireProperties)
{
- targetProperties = logProperties;
- usesLogger = true;
+ var logProperties = ra.LimitType
+ .GetRuntimeProperties()
+ .Where(c => c.CanWrite && c.PropertyType == typeof(ILogger) && c.SetMethod.IsPublic && !c.SetMethod.IsStatic)
+ .ToArray();
+
+ if (logProperties.Any())
+ {
+ targetProperties = logProperties;
+ usesLogger = true;
+ }
}
- }
- // Ignore components known to be without logger dependencies
- if (!usesLogger)
+ // Ignore components known to be without logger dependencies
+ if (!usesLogger)
+ return;
+ break;
+ case ProvidedInstanceActivator _:
+ //we cannot and should not affect provided instances
return;
+ default:
+ //most likely a DelegateActivator - or a custom one
+ if (_alwaysSupplyParameter)
+ break;
+ else
+ return;
}
registration.Preparing += (sender, args) =>
diff --git a/src/AutofacSerilogIntegration/SerilogContainerBuilderExtensions.cs b/src/AutofacSerilogIntegration/SerilogContainerBuilderExtensions.cs
index 0d1711e..0a03acc 100644
--- a/src/AutofacSerilogIntegration/SerilogContainerBuilderExtensions.cs
+++ b/src/AutofacSerilogIntegration/SerilogContainerBuilderExtensions.cs
@@ -19,11 +19,15 @@ public static class SerilogContainerBuilderExtensions
/// If true, properties on reflection-based components of type will
/// be injected.
///
+ ///
+ /// If true, the parameter containing will be injected even when registration cannot be verified to use it,
+ /// such as .
+ ///
/// An object supporting method chaining.
- public static IModuleRegistrar RegisterLogger(this ContainerBuilder builder, ILogger logger = null, bool autowireProperties = false, bool dispose = false)
+ public static IModuleRegistrar RegisterLogger(this ContainerBuilder builder, ILogger logger = null, bool autowireProperties = false, bool dispose = false, bool alwaysSupplyParameter = false)
{
- if (builder == null) throw new ArgumentNullException("builder");
- return builder.RegisterModule(new ContextualLoggingModule(logger, autowireProperties, dispose));
+ if (builder == null) throw new ArgumentNullException(nameof(builder));
+ return builder.RegisterModule(new ContextualLoggingModule(logger, autowireProperties, dispose, alwaysSupplyParameter));
}
}
}
diff --git a/test/AutofacSerilogIntegration.Tests/ActivatorTests.cs b/test/AutofacSerilogIntegration.Tests/ActivatorTests.cs
new file mode 100644
index 0000000..6ff1bec
--- /dev/null
+++ b/test/AutofacSerilogIntegration.Tests/ActivatorTests.cs
@@ -0,0 +1,129 @@
+using System;
+using System.Linq;
+using Autofac;
+using Autofac.Core;
+using Moq;
+using Serilog;
+using Xunit;
+
+namespace AutofacSerilogIntegration.Tests
+{
+ public class ActivatorTests
+ {
+ private readonly Mock _logger;
+
+ public ActivatorTests()
+ {
+ _logger = new Mock();
+ _logger.SetReturnsDefault(_logger.Object);
+ }
+
+ private void ResolveInstance(Action configureContainer, bool? alwaysSupplyParameter)
+ {
+ var containerBuilder = new ContainerBuilder();
+
+ if (alwaysSupplyParameter == null)
+ containerBuilder.RegisterLogger(_logger.Object);
+ else
+ containerBuilder.RegisterLogger(_logger.Object, alwaysSupplyParameter: alwaysSupplyParameter.Value);
+
+ containerBuilder.RegisterType>();
+ configureContainer(containerBuilder);
+ using (var container = containerBuilder.Build())
+ {
+ container.Resolve>();
+ }
+ }
+
+ private void VerifyLoggerCreation(Func times)
+ => _logger.Verify(logger => logger.ForContext(typeof(TContext)), times);
+
+ [Theory]
+ [InlineData(null)]
+ [InlineData(false)]
+ [InlineData(true)]
+ public void ReflectionActivator_DependencyWithLogger_ShouldCreateLogger(bool? alwaysSupplyParameter)
+ {
+ ResolveInstance(containerBuilder => containerBuilder.RegisterType(), alwaysSupplyParameter);
+ VerifyLoggerCreation(Times.AtLeastOnce);
+ }
+
+ [Theory]
+ [InlineData(null)]
+ [InlineData(false)]
+ [InlineData(true)]
+ public void ReflectionActivator_DependencyWithoutLogger_ShouldNotCreateLogger(bool? alwaysSupplyParameter)
+ {
+ ResolveInstance(containerBuilder => containerBuilder.RegisterType(), alwaysSupplyParameter);
+ VerifyLoggerCreation(Times.Never);
+ }
+
+ [Theory]
+ [InlineData(null)]
+ [InlineData(false)]
+ [InlineData(true)]
+ public void ProvidedInstanceActivator_ShouldNotCreateLogger(bool? alwaysSupplyParameter)
+ {
+ ResolveInstance(containerBuilder => containerBuilder.RegisterInstance(new DependencyWithoutLogger()), alwaysSupplyParameter);
+ VerifyLoggerCreation(Times.Never);
+ }
+
+ [Theory]
+ [InlineData(null)]
+ [InlineData(false)]
+ public void DelegateActivator_ShouldNotCreateLogger(bool? alwaysSupplyParameter)
+ {
+ ResolveInstance(containerBuilder => containerBuilder.Register(_ => new DependencyWithoutLogger()), alwaysSupplyParameter);
+ VerifyLoggerCreation(Times.Never);
+ }
+
+ [Theory]
+ [InlineData(null)]
+ [InlineData(false)]
+ public void DelegateActivator_ShouldNotPassParameter(bool? alwaysSupplyParameter)
+ {
+ Parameter[] parameters = null;
+ ResolveInstance(containerBuilder => containerBuilder.Register((_, pp) =>
+ {
+ parameters = pp.ToArray();
+ return new DependencyWithoutLogger();
+ }), alwaysSupplyParameter);
+ Assert.NotNull(parameters);
+ Assert.Empty(parameters);
+ }
+
+ [Theory]
+ [InlineData(true)]
+ public void DelegateActivator_WhenForced_ShouldPassParameter(bool? alwaysSupplyParameter)
+ {
+ Parameter[] parameters = null;
+ ResolveInstance(containerBuilder => containerBuilder.Register((_, pp) =>
+ {
+ parameters = pp.ToArray();
+ return new DependencyWithoutLogger();
+ }), alwaysSupplyParameter);
+ Assert.NotNull(parameters);
+ var value = Assert.Single(parameters
+ .OfType()
+ .Where(p => p.Type == typeof(ILogger))
+ )?.Value;
+ Assert.IsAssignableFrom(value);
+ }
+
+ private class Component
+ {
+ public Component(TDependency dependency)
+ {
+ }
+ }
+
+ private class DependencyWithLogger
+ {
+ public DependencyWithLogger(ILogger logger)
+ {
+ }
+ }
+
+ private class DependencyWithoutLogger {}
+ }
+}