I am trying to start using middleware and creating a logger for a project and thought the autofac log4net example was a good starting point as the project already is making use of autofac, but I am not being able to do so. I have the following classes:
using System;
using System.Linq;
using System.Reflection;
using Autofac;
using Autofac.Core;
using Autofac.Core.Registration;
using Autofac.Core.Resolving.Pipeline;
using log4net;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace TestProject1
{
public class TestMiddlewareModule : Autofac.Module
{
private readonly IResolveMiddleware middleware;
public TestMiddlewareModule(IResolveMiddleware middleware)
{
this.middleware = middleware;
}
protected override void AttachToComponentRegistration(IComponentRegistryBuilder componentRegistryBuilder,
IComponentRegistration registration)
{
// Attach to the registration's pipeline build.
registration.PipelineBuilding += (sender, pipeline) =>
{
// Add our middleware to the pipeline.
pipeline.Use(middleware);
};
}
}
public class TestLog4NetMiddleware : IResolveMiddleware
{
public PipelinePhase Phase => PipelinePhase.ParameterSelection;
public void Execute(ResolveRequestContext context, Action<ResolveRequestContext> next)
{
// Add our parameters.
context.ChangeParameters(context.Parameters.Union(
new[]
{
new ResolvedParameter(
(p, i) => p.ParameterType == typeof(ILog),
(p, i) => LogManager.GetLogger(p.Member.DeclaringType)
),
}));
// Continue the resolve.
next(context);
// Has an instance been activated?
if (context.NewInstanceActivated)
{
var instanceType = context.Instance.GetType();
// Get all the injectable properties to set.
// If you wanted to ensure the properties were only UNSET properties,
// here's where you'd do it.
var properties = instanceType
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(p => p.PropertyType == typeof(ILog) && p.CanWrite && p.GetIndexParameters().Length == 0);
// Set the properties located.
foreach (var propToSet in properties)
{
propToSet.SetValue(context.Instance, LogManager.GetLogger(instanceType), null);
}
}
}
}
[TestClass]
public class UnitTestLog4Net
{
public ILog logger { get; set; }
public TestContext TestContext { get; set; }
// Create your builder.
private static ContainerBuilder container = new ContainerBuilder();
private static IContainer builder;
protected ILifetimeScope scope;
[TestMethod]
public void TestMethodLog4Net()
{
container.RegisterType<TestLog4NetMiddleware>()
.As<IResolveMiddleware>()
.AsSelf()
;
container.RegisterServiceMiddleware<Log4NetMiddleware>(new Log4NetMiddleware())
//.AsImplementedInterfaces()
;
container.RegisterAssemblyModules(Assembly.GetExecutingAssembly());
builder = container.Build();
scope = builder.BeginLifetimeScope();
logger.Info("TEST");
}
}
}
However the test always fails with:
TestProject1.UnitTestLog4Net.TestMethodLog4Net threw exception: Autofac.Core.DependencyResolutionException: An exception was thrown while activating λ:Autofac.Core.IModule[] -> TestProject1.TestMiddlewareModule. ---> Autofac.Core.DependencyResolutionException: None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'TestProject1.TestMiddlewareModule' can be invoked with the available services and parameters: Cannot resolve parameter 'Autofac.Core.Resolving.Pipeline.IResolveMiddleware middleware' of constructor 'Void .ctor(Autofac.Core.Resolving.Pipeline.IResolveMiddleware)'.
But the line container.RegisterType<TestLog4NetMiddleware>().As<IResolveMiddleware>().AsSelf();
should have registered TestLog4NetMiddleware
as a valid IResolveMiddleware
What am I doing wrong?
Per the documentation on modules:
Modules do not, themselves, go through dependency injection. They are used to configure the container, they are not actually registered and resolved like other components. If your module takes a constructor parameter, for example, you need to pass that in yourself. It won’t come from the container.
Thus, to get the middleware in, you need to be a little more manual than using assembly scanning.
builder.RegisterModule(
new MiddlewareModule(
new Log4NetMiddleware()));