我有两个绑定:
Bind<ICache>().ToMethod(ctx => FactoryMethods.CreateCache(
ctx.Kernel.Get<IXXX>(),
ctx.Kernel.Get<IYYY>()))
.WhenTargetHas<SharedCacheAttribute>()
.InSingletonScope()
.Named(BindingNames.SHARED_CACHE);
Bind<ICache>().ToMethod(ctx => FactoryMethods.CreateTwoTierCache(
ctx.Kernel.Get<ICache>(BindingNames.SHARED_CACHE),
ctx.Kernel.Get<IZZZ>()))
.InSingletonScope();
本质上,这个想法是我有一个共享缓存(在第一个绑定中定义),但大多数时候我希望类使用两层缓存,它是相同的接口(ICache
)。因此,我使用属性约束限制共享缓存的使用(需要直接访问共享缓存的类只能使用 [SharedCache]
)。
现在,问题是第二个绑定,特别是这一行:
ctx.Kernel.Get<ICache>(BindingNames.SHARED_CACHE),
引发一个异常,指出没有匹配的绑定可用,大概是因为第一个绑定的属性约束。
如何将第一个绑定的解析结果注入到第二个绑定的工厂方法中?
解决方法:
目前,我在第一个绑定上使用Parameter
和更复杂的基于 When()
的约束。我的绑定现在如下所示:
Bind<ICache>().ToMethod(ctx => FactoryMethods.CreateCache(
ctx.Kernel.Get<IXXX>(),
ctx.Kernel.Get<IYYY>()))
.When(o => (o.Target != null &&
o.Target.GetCustomAttributes(typeof (SharedCacheAttribute), false).Any()) ||
o.Parameters.Any(p => p.Name == ParameterNames.GET_SHARED_CACHE))
.InSingletonScope();
Bind<ICache>().ToMethod(ctx => FactoryMethods.CreateTwoTierCache(
ctx.Kernel.Get<ICache>(new Parameter(ParameterNames.GET_SHARED_CACHE, true, true)),
ctx.Kernel.Get<IZZZ>()))
.InSingletonScope();
它按预期工作,但语法非常复杂。此外,我本来希望Parameter
构造函数的"shouldInherit"参数必须设置为 false
以防止将 GET_SHARED_CACHE 参数传递给子请求。碰巧的是,将其设置为 false
最终会导致StackOverflowException
,因为当设置为 false 时,参数会在请求中持久保存。将其设置为 true
会导致它不会传播 - 与我的预期相反。
另一种方法是用NamedAttribute
替换SharedCacheAttribute
。下面是一个示例:
//bindings
Bind<ICache>().ToMethod(ctx => FactoryMethods.CreateCache(
ctx.Kernel.Get<IXXX>(),
ctx.Kernel.Get<IYYY>()))
.InSingletonScope()
.Named(BindingNames.SHARED_CACHE);
Bind<ICache>().ToMethod(ctx => FactoryMethods.CreateTwoTierCache(
ctx.Kernel.Get<ICache>(BindingNames.SHARED_CACHE),
ctx.Kernel.Get<IZZZ>()))
.InSingletonScope();
// cache users
public class UsesSharedCache
{
public UsesSharedCache([Named(BindingNames.SHARED_CACHE)] ICache sharedCache)
{
}
}
public class UsesDefaultCache
{
public UsesDefaultCache(ICache defaultCache)
{
}
}
另一种选择是 IProvider
.绑定将如下所示:
Bind<ICache>().ToProvider<CacheProvider>();
CacheProvider
将包含用于确定是检索"默认"还是共享缓存的逻辑。它需要检查属性,然后解析并返回相应的实例。因此,ICache
还需要两个命名绑定:
Bind<ICache>().ToMethod(...).Named("default")
.BindingConfiguration.IsImplicit = true;
Bind<ICache>().ToMethod(...).Named("shared");
.BindingConfiguration.IsImplicit = true;
备注:.BindingConfiguration.IsImplicit = true;
是必要的,因为否则 ninject 认为所有绑定都满足了对ICache
(没有名称)的请求 - 并抛出异常。请求只需要由提供程序填充。