问题描述
我正在尝试从NInject迁移到Autofac,并且遇到了一个看似简单的问题。我想迁移此NInject绑定:
Kernel.Bind(typeof(IOptions<>)).ToMethod(c => CreateOptions(c.Request.Service));
换句话说,当需要封闭的IOptions<>
时,请以请求的类型调用CreateOptions()
并让我创建实现。
我在Autofac中想到的最好的方法是:
- 创建
IOptions<>
的虚拟实现,让Autofac用RegisterGeneric()
构造它,然后在 OnActivating 事件中使用ReplaceInstance()
。 - 创建一个按类型过滤的
IRegistrationSource
,然后调用我的工厂方法。
方法(1)似乎很愚蠢-当然我不必为了获得其类型而创建未使用的对象吗?
方法(2)可以,但是它是大量的代码(见下文),如果我要设置范围等内容,它会变得更大。
在两种情况下,简单地委派给工厂方法的代码量似乎都很疯狂。有更好的方法吗?
(为完整起见,以下是我的IRegistrationSource
。请注意,必须重写这两个抽象成员才能获得NInject功能。)
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;
}
解决方法
你让我想到了这个!
除了您现在已经具备的机制之外,我想不出更好的方法来解决此问题。您可以使用开放的通用装饰器来做一些事情,但是您仍然需要虚拟类型,它并不比OnActivating解决方案好多少。
这是种,它是OnActivating事件的用途,它可以对激活实例进行高级替换。
如果您愿意作为功能请求在我们的回购(http://github.com/autofac/autofac)中提出问题,请提供所有详细信息,我愿意讨论如果添加它,“理想”行为的外观到库中,以及用例是否足够通用以便添加。