1

I am looking to intercept the creation of instances that implement a certain interface, or have a certain attribute. I am able to do something similiar with the interception extension, but that only seems to do method and property interception.

Here is how I can intercept method and property calls, but it doesn't intercept the constructor call:

_kernel.Bind<IInterceptor>().To<LogInterceptor>().InSingletonScope();
_kernel.Intercept(x =>
{
    if (x.Plan.Type.GetInterface(typeof(ITriggerLoggingInterception).FullName) != null)
    {
        return true;
    }

    return false;
}).With<LogInterceptor>();
Eric Scherrer
  • 3,328
  • 1
  • 19
  • 34
  • I have been looking and still can't find a way, which is usually a sign I am trying to do something I shouldn't be. – Eric Scherrer Jan 14 '15 at 19:46
  • What do you want to achieve by intercepting the ctor? How flexible does it need to be? These might be alternatives: `.ToProvider()` bindings or the `.OnActivation()` binding extension. – BatteryBackupUnit Jan 15 '15 at 09:28
  • I'm working on a plugin based Caliburn Micro app. There is a eventAggregator component that I want to make easy for devs to leverage. Normally in order to use this component you must get an eventAggregator injected in and call Subcribe() on it, then implement the IHandle<> interface which tells the eventAggregator to call those event handlers. To make it easy, I want to intercept the post constructor call, and if the class implements the IHandle<> interface then call Subscribe() for it. This would be good because I can see devs forgetting to do this and wasting time tracking it down. – Eric Scherrer Jan 15 '15 at 15:59
  • ok. Who's / who / when is the binding created? We used an event broker. And registering publishers/subscribers with it was done by a custom `RegisterBrokeredEvents()` extension which extended ninject's `OnActivation`. This is called post-ctor. – BatteryBackupUnit Jan 15 '15 at 17:15

1 Answers1

3

As you found out for yourself, what comes closest to doing something on instanciation for every binding - without requiring the binding to be altered - is an IActivationStrategy.

for example (example taken from here:

public class StartableStrategy : ActivationStrategy
{
  public override void Activate(IContext context, InstanceReference reference)
  {
    reference.IfInstanceIs<IStartable>(x => x.Start());
  }

  public override void Deactivate(IContext context, InstanceReference reference)
  {
    reference.IfInstanceIs<IStartable>(x => x.Stop());
  }
}

which is added to the ninject kernel the following way:

kernel.Components.Add<IActivationStrategy, StartableActivationStrategy>();

Alternative - binding syntax sugar

let me go into more detail about the OnActivation() extension i mentioned in the comments:

    public static IBindingOnSyntax<T> RegisterEvents<T>(this IBindingOnSyntax<T> binding)
    {
        // todo check whether <T> implements the IHandle<> interface, if not throw exception
        return binding
            .OnActivation((ctx, instance) => ctx.Kernel.Get<EventAggregator>().Subscribe(instance));
    }

this you would employ manually to the binding:

kernel.Bind<FooViewModel>().ToSelf()
      .RegisterEvents()
      .InSingletonScope();

(the InSingletonScope() isn't needed - it's just to show that you can use the other binding extensions/features as before).

Now i think you want to employ this rather "by convention". If you create your bindings by convention (ninject.extensions.conventions), you can use an IBindingGenerator to create the binding accordingly (with or without the call to RegisterEvents). If not, it get's trickier. I'd say you'd have to extend ninject's pipeline.

BatteryBackupUnit
  • 12,934
  • 1
  • 42
  • 68
  • The bindings get created in two places. The app binds the basic stuff like logger factory when it starts up, then it loops through plug-ins and gives each a chance to add it's own bindings. – Eric Scherrer Jan 15 '15 at 18:22
  • So I guess the question is if it is better to have them wire it up in the class or the binding. Still not the goal of it happening for them, but pretty good. Thanks. – Eric Scherrer Jan 15 '15 at 18:25
  • cool, didn't know about that one! How about you create an answer yourself and accept it? I think it might be the better approach for what you wanted to achieve. There's also an entry in the ninject wiki [here](https://github.com/ninject/Ninject/wiki/Component-Extension-Points#iactivationstrategy) – BatteryBackupUnit Jan 15 '15 at 21:36
  • If you just edit and put that in then the answer will cover all possibilities. Unfortunately it's not working out for me though because I also use interception. The castle generated proxy does not implement the same interfaces as the concrete type, so EventAggregator is just ignoring it. Not having any luck getting the underlying proxy's target, even with dirty hacks. Can't put the IHandle<> on the interface because not all implementations may need to subscribe. I think the devs will just have to subscribe to events themselves! – Eric Scherrer Jan 15 '15 at 21:51
  • If I am correct overridden `Activate` method is called when the required instance is created. But May I know when overridden `Deactivate` method is called and how can I call it explicitly ? – Shaiju T Sep 25 '17 at 14:14
  • 1
    @stom that depends on the scope of the binding. For the default (`InTransientScope`) the answer is *never*. For (`InSingletonScope`) it is when the kernel is disposed. For others it's when the scope ends - and under circumstances these can be delayed because depending on the use case this is only detected by a periodically running background job that check whether the `WeakReference` to the scope `IsAlive`. If you implement your own scope you can have the scope object implement `INotifyWhenDisposed` for deterministic behavior (it's a Ninject interface). – BatteryBackupUnit Sep 26 '17 at 12:21