I'm trying to migrate to Autofac from NInject, and I'm running into a seemingly simple problem. I want to migrate this NInject binding:
Kernel.Bind(typeof(IOptions<>)).ToMethod(c => CreateOptions(c.Request.Service));
In other words, when a closed IOptions<>
is required, call CreateOptions()
with the requested type and let me create the implementation.
The best I've come up with in Autofac is either:
IOptions<>
, let Autofac construct it with RegisterGeneric()
, then use ReplaceInstance()
in the OnActivating event.IRegistrationSource
that filters by type and then calls my factory method.Method (1) seems dumb - surely I don't have to create an unused object just to get its type?
Method (2) is okay, but it's a mass of code (see below), and it gets even bigger if I want to set things like scope, etc.
In both cases the amount of code to simply delegate to a factory method seems wild. Is there a better way?
(For completeness, below is my IRegistrationSource
. Note the two abstract members that must be overridden to get the NInject functionality.)
public abstract class DelegatingRegistrationSource : IRegistrationSource
{
protected abstract bool CanDelegate(Type limitType);
protected abstract DelegateActivator CreateDelegate(Type limitType);
public IEnumerable<IComponentRegistration> RegistrationsFor(Service service,
Func<Service, IEnumerable<IComponentRegistration>> registrationAccessor)
{
if (!(service is IServiceWithType swt) || !CanDelegate(swt.ServiceType))
return Enumerable.Empty<IComponentRegistration>();
var registration = new ComponentRegistration(
Guid.NewGuid(),
CreateDelegate(swt.ServiceType),
new CurrentScopeLifetime(),
InstanceSharing.None,
InstanceOwnership.OwnedByLifetimeScope,
new[] { service },
new Dictionary<string, object>());
return new IComponentRegistration[] { registration };
}
public bool IsAdapterForIndividualComponents => false;
}
You sort of got me thinking with this one!
I can't think of a better way to solve this other than the mechanisms you've already arrived at right now. You could do something with open generic decorators, but you would still need the dummy type, it's not much better than the OnActivating solution.
That is sort of what the OnActivating event is for, doing advanced replacement of the activating instance.
If you are willing to raise an issue in our repo (http://github.com/autofac/autofac) as a Feature Request, with all the detail, I'd be open to discussing how the 'ideal' behaviour might look if we added it to the library, and whether the usecase is common enough to add in.