手动解析由属性约束绑定的依赖项

Manually resolving dependencies bound by attribute constraints

我有两个绑定:

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 最终会导致 WhosebugException,因为当此设置为 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 将包含确定是检索 "default" 还是共享缓存的逻辑。它需要检查属性,然后解析并 return 相应的实例。因此 ICache:

还需要两个命名绑定
Bind<ICache>().ToMethod(...).Named("default")
              .BindingConfiguration.IsImplicit = true;
Bind<ICache>().ToMethod(...).Named("shared");
              .BindingConfiguration.IsImplicit = true;

备注:.BindingConfiguration.IsImplicit = true; 是必需的,否则 ninject 认为 ICache(没有名称)的请求由所有绑定实现 - 并抛出异常。请求只需要由提供者完成。