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

本文关键字:绑定 依赖 约束 属性 | 更新日期: 2023-09-27 18:36:28

我有两个绑定:

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(没有名称)的请求 - 并抛出异常。请求只需要由提供程序填充。