SimpleInjector - Register a type for all it's interfaces - dependency-injection

Is it possible to register a type for all it's implementing interfaces? E.g, I have a:
public class Bow : IWeapon
{
#region IWeapon Members
public string Attack()
{
return "Shooted with a bow";
}
#endregion
}
public class HumanFighter
{
private readonly IWeapon weapon = null;
public HumanFighter(IWeapon weapon)
{
this.weapon = weapon;
}
public string Fight()
{
return this.weapon.Attack();
}
}
[Test]
public void Test2b()
{
Container container = new Container();
container.RegisterSingle<Bow>();
container.RegisterSingle<HumanFighter>();
// this would match the IWeapon to the Bow, as it
// is implemented by Bow
var humanFighter1 = container.GetInstance<HumanFighter>();
string s = humanFighter1.Fight();
}

It completely depends on your needs, but typically you need to use the Container's non-generic registration method. You can define your own LINQ queries to query the application's metadata to get the proper types, and register them using the non-generic registration methods. Here's an example:
var weaponsAssembly = typeof(Bow).Assembly;
var registrations =
from type in weaponsAssembly.GetExportedTypes()
where type.Namespace.Contains(".Weapons")
from service in type.GetInterfaces()
select new { Service = service, Implementation = type };
foreach (var reg in registrations)
{
container.Register(reg.Service, reg.Implementation);
}
If you need to batch-register a set of implementations, based on a shared generic interface, you can use the RegisterManyForOpenGeneric extension method:
// include the SimpleInjector.Extensions namespace.
container.RegisterManyForOpenGeneric(typeof(IValidator<>),
typeof(IValidator<>).Assembly);
This will look for all (non-generic) public types in the supplied assembly that implement IValidator<T> and registers each of them by their closed-generic implementation. If an type implements multiple closed-generic versions of IValidator<T>, all versions will be registered. Take a look at the following example:
interface IValidator<T> { }
class MultiVal1 : IValidator<Customer>, IValidator<Order> { }
class MultiVal2 : IValidator<User>, IValidator<Employee> { }
container.RegisterManyForOpenGeneric(typeof(IValidator<>),
typeof(IValidator<>).Assembly);
Assuming the given interface and class definitions, the shown RegisterManyForOpenGeneric registration is equivalent to the following manual registration:
container.Register<IValidator<Customer>, MultiVal1>();
container.Register<IValidator<Order>, MultiVal1>();
container.Register<IValidator<User>, MultiVal2>();
container.Register<IValidator<Employee>, MultiVal2>();
It would also be easy to add convenient extension methods. Take for instance the following extension method that allows you to register a single implementation by all its implemented interfaces:
public static void RegisterAsImplementedInterfaces<TImpl>(
this Container container)
{
foreach (var service in typeof(TImpl).GetInterfaces())
{
container.Register(service, typeof(TImpl));
}
}
It can be used as follows:
container.RegisterAsImplementedInterfaces<Sword>();

Related

How can I get Ninject to inject a specific SerialPort instance into a specific instance of another class?

[This is for a Windows 10 IoT UWP app on a Raspberry Pi 2]:
Concretely, I'm trying to create two serial ports and link each one to a device driver for device that has a serial connection (I have two identical devices and a serial port to talk to each). I have a class (call it DeviceDriver) that implements an IDeviceDriver interface for this type of device. My hardware configuration also includes an external chip that has multiple serial ports. I have a class SerialPort for those and they implement an ISerialPort interface.
I need two instances of DeviceDriver as I have two devices, and two instances of SerialPort - one for each device. I can get Ninject to make one serialport and pass the ISerialPort object to the DeviceDriver constructor. Where I am stuck is that I want two DeviceDriver objects; one that gets linked to a SerialPort (COM1) and the other gets linked to a separate SerialPort (COM2). Examples for Ninject show you can bind multiple different classes to one instance (a Shuriken and Sword can both be bound to IWeapon), but I don't see how to bind a COM1 serialport and a COM2 serialport to ISerialPort - it gives me a compilation error. So how do I create two instances of the same SerialPort class (with different constructor arguments to say one is COM1 and the other is COM2, I know how to specify constructor arguments already) and then tell Ninject which SerialPort to pass to two instances of a DeviceDriver class, where one needs COM1 and one needs COM2?
My DeviceDriver basically looks like this:
public class DeviceDriver :IDeviceDriver
{
ISerialPort m_localPort;
public DeviceDriver(ISerialPort port)
{
m_localPort = port;
}
// Other stuff
// ...
}
Anybody have any thoughts how I can do this? The following link is the only thing I've found, but they are talking about Unity and XML configuration files and it seems overly complex for what I'm trying to do.
Initialising configurable objects with dependency injection container
Thanks!
Let's say we've got the following implementation:
public class SerialPortAddress
{
public SerialPortAddress(string address)
{
this.Address = address;
}
public string Address { get; }
}
public interface ISerialPort
{
SerialPortAddress Address { get; }
}
public class SerialPort : ISerialPort
{
public SerialPort(SerialPortAddress address)
{
this.Address = address;
}
public SerialPortAddress Address { get; }
}
public interface IDeviceDriver
{
ISerialPort SerialPort { get; }
}
public class DeviceDriver : IDeviceDriver
{
public DeviceDriver(ISerialPort serialPort)
{
SerialPort = serialPort;
}
public ISerialPort SerialPort { get; }
}
Multi-Injection
We can then create the bindings as follows and retrieve a list of IDeviceDrivers with their serial ports as follows:
public class Test
{
[Fact]
public void Bla()
{
var com1 = new SerialPortAddress("COM1");
var com2 = new SerialPortAddress("COM2");
var kernel = new StandardKernel();
kernel.Bind<ISerialPort>().To<SerialPort>();
kernel.Bind<IDeviceDriver>().To<DeviceDriver>()
.WithParameter(new TypeMatchingConstructorArgument(
typeof(SerialPortAddress),
(ctx, target) => com1, true));
kernel.Bind<IDeviceDriver>().To<DeviceDriver>()
.WithParameter(new TypeMatchingConstructorArgument(
typeof(SerialPortAddress),
(ctx, target) => com2, true));
var deviceDrivers = kernel.Get<List<IDeviceDriver>>();
deviceDrivers.Should().HaveCount(2)
.And.Contain(x => x.SerialPort.Address == com1)
.And.Contain(x => x.SerialPort.Address == com2);
}
}
Also see Multi Injection
Named Bindings
Alternatively, if you need to know which IDeviceDrivers is which, you can also use named bindings:
[Fact]
public void NamedBindings()
{
const string DeviceDriver1 = "DeviceDriver1";
const string DeviceDriver2 = "DeviceDriver2";
var com1 = new SerialPortAddress("COM1");
var com2 = new SerialPortAddress("COM2");
var kernel = new StandardKernel();
kernel.Bind<ISerialPort>().To<SerialPort>();
kernel.Bind<IDeviceDriver>().To<DeviceDriver>()
.Named(DeviceDriver1)
.WithParameter(new TypeMatchingConstructorArgument(
typeof(SerialPortAddress),
(ctx, target) => com1, true));
kernel.Bind<IDeviceDriver>().To<DeviceDriver>()
.Named(DeviceDriver2)
.WithParameter(new TypeMatchingConstructorArgument(
typeof(SerialPortAddress),
(ctx, target) => com2, true));
kernel.Get<IDeviceDriver>(DeviceDriver1).SerialPort.Address.Should().Be(com1);
kernel.Get<IDeviceDriver>(DeviceDriver2).SerialPort.Address.Should().Be(com2);
}
Factory
Finally, you could also create the components by factory, which requires a factory interface to begin with:
public interface IDeviceDriverFactory
{
IDeviceDriver Create(SerialPortAddress address);
}
using Ninject.Extensions.Factory we can now do the following:
[Fact]
public void Factory()
{
var com1 = new SerialPortAddress("COM1");
var com2 = new SerialPortAddress("COM2");
var kernel = new StandardKernel();
kernel.Bind<ISerialPort>().To<SerialPort>();
kernel.Bind<IDeviceDriver>().To<DeviceDriver>();
kernel.Bind<IDeviceDriverFactory>()
.ToFactory(() => new TypeMatchingArgumentInheritanceInstanceProvider());
var factory = kernel.Get<IDeviceDriverFactory>();
factory.Create(com1).SerialPort.Address.Should().Be(com1);
factory.Create(com2).SerialPort.Address.Should().Be(com2);
}
EDIT: Ninject.Extension.Factory may not run on the raspberry pi.
If that's the case you might need to implement the factory yourself:
public class DeviceDriverFactory : IDeviceDriverFactory
{
private readonly IResolutionRoot resolutionRoot;
public DeviceDriverFactory(IResolutionRoot resolutionRoot)
{
this.resolutionRoot = resolutionRoot;
}
public IDeviceDriver Create(SerialPortAddress address)
{
var serialPortAddressParameter = new TypeMatchingConstructorArgument(
typeof(SerialPortAddress),
(ctx, t) => address)
this.resolutionRoot.Get<IDeviceDriver>(serialPortAddressParameter);
}
}
Bind<IDeviceDriverFactory>().To<DeviceDriverFactory>();
I'm not familiar Ninject or Unity, but Castle Windsor has a lifestyle called Pooled, which will create up to a specified number of instances and then return those instances to the pool of instances after they've been released. When using this lifestyle, Windsor will create as many objects as are requested up to the limit specified, and then either recycle the instance (if you've derived from IRecyclable and implemented the Recycle() method) or dispose of it normally.
You can have your components created using a simple factory method that provides the correct constructor arguments, and then when they are returned to the pool they will be correctly configured.
EDIT:
If you're set on using Ninject, then I would solve this problem by injecting an ISerialPortFactory into the constructor of DeviceDriver and using that to create your ISerialPort objects. Since your DeviceDriver class doesn't care which ISerialPort it's using, the factory can be used to manage the instances that you need.
Your factory would look something like this:
public interface ISerialPortFactory
{
ISerialPort CreateNext();
}
public class SerialPortFactory : ISerialPortFactory
{
public ISerialPort CreateNext()
{
var serialPortConfiguration = GetNextConfiguration();
return new SerialPort(serialPortConfiguration);
}
private GetNextConfiguration()
{
// you could manage some kind of internal registry of COMx configurations here
}
}
And your client DeviceDriver class would look like this:
public class DeviceDriver : IDeviceDriver
{
public DeviceDriver(ISerialPortFactory factory)
{
m_localPort = factory.CreateNext();
}
}
The abstract factory method is sort of a heavy-handed way of getting what you want, but it's a surefire way to get exactly what you need since you have complete control over it. Its main use case is to resolve dependencies where you don't necessarily know the exact implementation you want until runtime.

Autofac get decorated QueryHandler by convention based on constructor parameter name?

We inject IQueryHandler<TQUery,TResult> into our MVC controllers. We globally register all of these in the container
We have written a decorator that can cache the results of IQueryHandler.
We want to sometimes get cached reults and other times not from the same handler.
Is it possible to conditionally get a decorated handler based on the name of the constructor parameter. e.g. inject IQueryHandler<UnemployedQuery, IEnumerable<People>> cachedPeopleHandler if we prefix constructor parameter name with cached we actually get it wrapped with decorator?
Just trying to use a more convention over configuration approach to simplify things.
Yes it's possible to do it. Below is a simple working example on how you can achieve it:
class Program
{
public interface IQueryHandler{}
private class QueryHandler : IQueryHandler
{
}
private class CacheQueryHandler : IQueryHandler
{
}
public interface IService
{
}
private class Service : IService
{
private readonly IQueryHandler _queryHandler;
private readonly IQueryHandler _cacheQueryHandler;
public Service(IQueryHandler queryHandler, IQueryHandler cacheQueryHandler)
{
_queryHandler = queryHandler;
_cacheQueryHandler = cacheQueryHandler;
}
public override string ToString()
{
return string.Format("_queryHandler is {0}; _cacheQueryHandler is {1}", _queryHandler,
_cacheQueryHandler);
}
}
static void Main(string[] args)
{
var builder = new ContainerBuilder();
// Register the dependency
builder.RegisterType<QueryHandler>().As<IQueryHandler>();
// Register the decorator of the dependency
builder.RegisterType<CacheQueryHandler>().Keyed<IQueryHandler>("cache");
// Register the service implementation
builder.RegisterType<Service>().AsSelf();
// Register the interface of the service
builder.Register(c =>
{
var ctor = typeof (Service).GetConstructors()[0];
var parameters =
ctor.GetParameters()
.Where(p => p.Name.StartsWith("cache"))
.Select(p => new NamedParameter(p.Name, c.ResolveKeyed("cache", p.ParameterType)));
return c.Resolve<Service>(parameters);
}).As<IService>();
using (var container = builder.Build())
{
var service = container.Resolve<IService>();
Console.WriteLine(service.ToString());
Console.ReadKey();
}
}
}
Update:
Basically you need to:
1. Think up a general convention. Prefix "cache" of ctor parameter name in your case.
2. Register your dependencies as usual.
3. Register your decorators, so they don't overwrite your original dependencies and you can easily resolve them basing on your convention. e.g. Keyed, Named, via Attribute, etc.
4. Register you actual implementation of class that uses decorators
5. Register your interface that describes the class via lambda expression that has all magic inside.
Note: I provided just a simple and working example. It's on you to make it nice, easy to use and fast e.g. make it as an extension, generic, cache reflection results etc. It's not difficult anyway.
Thanks.

Can I do piece-wise configuration of scoping for my objects in Ninject?

We have several cases where we are providing services in code libraries where we know scoping and lifetime rules for the service providers in the code library. We would like to configure that information in the library itself without having to have that knowledge bubbled up to the composition root.
I have been unable to figure out if it's possible to implement this with the current version of Ninject.
using System;
using System.Diagnostics.CodeAnalysis;
using Ninject;
using Ninject.Extensions.Conventions;
using NUnit.Framework;
using Ninject.Modules;
[TestFixture]
public class Spike
{
private IKernel kernel;
[SetUp]
public void SetUp()
{
this.kernel = new StandardKernel();
this.kernel.Load(new Registry());
this.kernel.Bind(x => x
.FromThisAssembly()
.SelectAllClasses()
.BindAllInterfaces()
);
}
[TearDown]
public void TearDown()
{
Thing1.ResetCounts();
}
[Test]
public void GetThing1AndThing2()
{
// arrange
var thing1 = this.kernel.Get<Thing1>();
var thing2 = this.kernel.Get<Thing1>();
// act
thing1.DoTheWork();
thing2.DoTheWork();
// assert
Assert.AreEqual(1, Thing1.ConstructorCount, "wrong number of constructor invocations");
Assert.AreEqual(2, Thing1.DoTheWorkCount, "wrong number of method invocations");
}
[Test]
public void GetIThing1AndIThing2()
{
// arrange
var thing1 = this.kernel.Get<IThing1>();
var thing2 = this.kernel.Get<IThing1>();
// act
thing1.DoTheWork();
thing2.DoTheWork();
// assert
Assert.AreEqual(1, Thing1.ConstructorCount, "wrong number of constructor invocations");
Assert.AreEqual(2, Thing1.DoTheWorkCount, "wrong number of method invocations");
}
public class Registry : NinjectModule
{
public override void Load()
{
Bind<Thing1>().ToSelf().InSingletonScope();
}
}
public interface IThing1
{
void DoTheWork();
}
public class Thing1 : IThing1
{
public static int ConstructorCount { get; set; }
public static int DoTheWorkCount { get; set; }
public Thing1()
{
Console.WriteLine("Thing1.ctor underway");
++Thing1.ConstructorCount;
}
public void DoTheWork()
{
Console.WriteLine("Thing1.DoTheWork underway");
++Thing1.DoTheWorkCount;
}
public static void ResetCounts()
{
Thing1.ConstructorCount = 0;
Thing1.DoTheWorkCount = 0;
}
}
}
In this test case, the ilbrary is represented by the Registry, Thing1, and IThing1 classes. The user of the library is the test fixture, where the Spike.SetUp() method shows the code we'd ideally like the library user to write (where they'd pass in a path containing the dll instead of new-ing up a Registry object).
With the code as written, fetching the Thing1 service multiple times in Spike.GetThing1AndThing2() exhibits the desired singleton behavior. Fetching the Thing1 service multiple times via its published interface as in Spike.GetIThing1AndIThing2() does not exhibit singleton behavior but rather constructs two separate Thing1 objects.
So is it possible to do what I'm asking: to specify the singleton behavior in the DLL itself while having the scan performed when the composition root is formed?
You need to introduce conventions. E.g. Add an attribute specifying the scope or use a naming convention so that you can identify the scope from the name.
Then setup the binding conventions correctly. E.g
this.kernel.Bind(x => x
.FromThisAssembly()
.SelectAllClasses()
.WithAttribute<SingletonAttribute>()
.BindAllInterfaces()
.Configure(binding => binding.InSingletonScope());
this.kernel.Bind(x => x
.FromThisAssembly()
.SelectAllClasses()
.WithAttribute<TransientAttribute>()
.BindAllInterfaces());

structuremap inject a dictionary list of interfaces

Say I have a list of protocol handlers, and the client service knows which protocol to use based on an enum value, it would be nice to selected the protocol from the list of i/fs passed in.
How can I achieve this in StructureMap?:
public EmailTransportService(interfaces...,
IDictionary<EmailAccountType, IEmailTransportHandler> transportHandlers)
At the moment, I'm using ObjectFactory with get named instance like so:
_emailTransportHandlers = new Dictionary<EmailAccountType, string>
{
{EmailAccountType.Pop3, "Pop3Handler"},
{EmailAccountType.IMAP, "IMapHandler"}
};
then resolving like so:
private IEmailTransportHandler GetTransportHandler(EmailAccountType accountType)
{
return ObjectFactory.GetNamedInstance<IEmailTransportHandler>(_emailTransportHandlers[accountType]);
}
but I don't like this as its difficult within my unit tests to verify the calls to the handlers.
My service registry looks like so:
public EmailTransportServiceRegistry()
{
Scan(x =>
{
....
});
For<IEmailTransportHandler>().Use<ActiveUpPop3Handler>().Named("Pop3Handler");
For<IEmailTransportHandler>().Use<ActiveUpIMap4Handler>().Named("IMapHandler");
}
So basically I'm relying on named instances based on the dictionary list of protocol types.
My solution was to have a static register method from the client service like so:
public static IDictionary<EmailAccountType, IEmailTransportHandler> RxHandlerRegistration()
{
return new Dictionary<EmailAccountType, IEmailTransportHandler>
{
// following registrations use ActiveUp library for pop3/imap (http://mailsystem.codeplex.com/)
{EmailAccountType.Pop3, ObjectFactory.GetInstance<ActiveUpPop3Handler>()},
{EmailAccountType.IMAP, ObjectFactory.GetInstance<ActiveUpIMap4Handler>()}
};
}
Then in the ServiceRegistry class:
public class EmailTransportServiceRegistry : ServiceRegistry
{
public EmailTransportServiceRegistry()
{
// other registries...
For<IDictionary<EmailAccountType, IEmailTransportHandler>>().Use(x => EmailTransportService.RxHandlerRegistration());
}
}

Passing in the type of the declaring class for NLog using Autofac

Following on from this question I would like autofac to inject the type of the declaring object into the constructor of my NLog service, so that it can correctly log which type is logging entries.
My NLogService class looks like this...
public class NLogService : ILogService
{
private readonly Logger _logger;
public NLogService(Type t)
{
var consumerType = t.DeclaringType.FullName;
_logger = LogManager.GetLogger(consumerType);
}
However it fails on app startup because it obviously cannot work out what to inject into the constructor of the NLogService with the following error...
None of the constructors found with
'Public binding flags' on type
'MyProduct.Domain.Services.Logging.NLogService'
can be invoked with the available
services and parameters: Cannot
resolve parameter 'System.Type t' of
constructor 'Void .ctor(System.Type)'.
So, my question is - how do i instruct autofac to inject the type of the calling class?
I tried this...
public NLogService(Type t)
{
var method = MethodBase.GetCurrentMethod();
Type consumingType = method.DeclaringType;
var consumerType = consumingType.FullName;
var consumerType = t.DeclaringType.FullName;
_logger = LogManager.GetLogger(consumerType);
}
But i just end up with MyProduct.Domain.Services.Logging.NLogService
What i want is the type of the class that is doing the actual logging.
i have already tried this suggestion and it didnt work for me either.
Could make your NLogService generic, i.e. NLogService<T> and use Autofac's open generics support?
Then you could do this:
public class NLogService<T> : ILogger<T>
{
private readonly Logger _logger;
public NLogService()
{
_logger = LogManager.GetLogger(typeof(T).FullName);
}
}
There is no real good way to do this with Autofac, because does not have support for 'context based injection' (which is what you are trying to do). There is a workaround, but it aint pretty...
What you can do is revert to property injection and define a base class or interface for that ILogService property. For instance, you can define the following interface:
public interface ILoggerContainer
{
public ILogService Logger { get; set; }
}
Now you can implement this interface on all types that need a logger:
public class Consumer : IConsumer, ILoggerContainer
{
public ILogService Logger { get; set; }
}
With this in place you can configure Autofac as follows:
builder.RegisterType<ILoggerContainer>()
.OnActivating(e =>
{
var type = typeof(LogService<>)
.MakeGenericType(e.Instance.GetType());
e.Instance.Logger = e.Context.Resolve(type);
});
Another workaround, that you may find cleaner is to inject an ILogger<T> with the same type as the type of the parent type:
public class Consumer : IConsumer
{
public Consumer(ILogger<Consumer> logger) { }
}
This makes the configuration much easier and prevents you from having to have a base class. Which one is most appropriate is up to you.
As I said, these are workarounds, but to be honest, you might need to reconsider your logging strategy in your application. Perhaps you are logging at too many places. In the applications I write there is hardly ever a need to log, and when I do, I write an logging message that is expressive enough so that there is no need to communicate the type that triggered the event. And when you log exception, you will always have a complete stack trace (and exception logging should almost only happen in the outer layer of your application and not within services anyway).
The following technique works well in our experience:
Create an attribute like below, which can be applied at class level or at the injection site:
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Class)]
public class LoggerAttribute : Attribute
{
public readonly string Name;
public LoggerAttribute(string name)
{
Name = name;
}
}
Create an Autofac module that you register with the ContainerBuilder:
public class LogInjectionModule : Module
{
protected override void AttachToComponentRegistration(IComponentRegistry registry, IComponentRegistration registration)
{
registration.Preparing += OnComponentPreparing;
}
static void OnComponentPreparing(object sender, PreparingEventArgs e)
{
var typePreparing = e.Component.Activator.LimitType;
// By default, the name supplied to the logging instance is the name of the type in which it is being injected into.
string loggerName = typePreparing.FullName;
//If there is a class-level logger attribute, then promote its supplied name value instead as the logger name to use.
var loggerAttribute = (LoggerAttribute)typePreparing.GetCustomAttributes(typeof(LoggerAttribute), true).FirstOrDefault();
if (loggerAttribute != null)
{
loggerName = loggerAttribute.Name;
}
e.Parameters = e.Parameters.Union(new Parameter[]
{
new ResolvedParameter(
(p, i) => p.ParameterType == typeof (Logger),
(p, i) =>
{
// If the parameter being injected has its own logger attribute, then promote its name value instead as the logger name to use.
loggerAttribute = (LoggerAttribute)
p.GetCustomAttributes(typeof(LoggerAttribute),true).FirstOrDefault();
if (loggerAttribute != null)
{
loggerName = loggerAttribute.Name;
}
// Return a new Logger instance for injection, parameterised with the most appropriate name which we have determined above.
return LogManager.GetLogger(loggerName);
}),
// Always make an unamed instance of Logger available for use in delegate-based registration e.g.: Register((c,p) => new Foo(p.TypedAs<Logger>())
new TypedParameter(typeof(Logger), LogManager.GetLogger(loggerName))
});
}
}
You can now inject a named Logger in any one of these ways depending on individual scenarios:
By default, the injected logger name will be given the full type name of the class it is injected into:
public class Foo
{
public Foo(Logger logger)
{
}
}
Use a constructor parameter [Logger] attribute to override the logger name:
public class Foo
{
public Foo([Logger("Meaningful Name")]Logger logger)
{
}
}
Use a class-level [Logger] attribute to set the same logger name override for all constructor overloads:
[Logger("Meaningful Name")]
public class Foo
{
public Foo(Logger logger, int something)
{
}
public Foo(Logger logger, int something, DateTime somethingElse)
{
}
}
Use constructor parameter [Logger] attributes on each constructor overload to set different logger names depending on the context of how you were constructed:
public class Foo
{
public Foo(Logger("Meaningful Name")]Logger logger, int something)
{
}
public Foo(Logger("Different Name")]Logger logger, int something, DateTime somethingElse)
{
}
}
IMPORTANT NOTE: If you register types to be resolved with logger constructor injection using Autofac's delegate registration, you MUST use the two parameter overload like so: Register((c,p) => new Foo(p.TypedAs<Logger>()).
Hope this helps!
It is possible to do this without generics.
However, please note that in Autofac 6.x, the resolution process has changed to use a resolve pipeline. This doesn't matter for most scenarios, but it does when you want to use the lifetime events like OnPreparing, etc. Most of the answers here on SO around overriding the Preparing event are very old and are now outdated. You can't override Preparing directly anymore.
There is an example on the Autofac documentation site doing this for log4net, and it works with NLog with only minor changes. Here is the basic idea:
public class Log4NetMiddleware : 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);
}
}
}
}
Please also note that you have to understand how middleware works in Autofac. The documentation is a good place to start.

Resources