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

时间:2015-01-06 10:31:25

标签: c# ninject

我有两个绑定:

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会导致它不会传播 - 与我预期的相反。

1 个答案:

答案 0 :(得分:2)

另一种方法是将SharedCacheAttribute替换为NamedAttribute。这是一个例子:

//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(没有名称)的请求 - 并抛出异常。该请求只需由提供商填写。