Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Interception feature #86

Closed
ktutnik opened this issue Feb 26, 2016 · 11 comments
Closed

Interception feature #86

ktutnik opened this issue Feb 26, 2016 · 11 comments

Comments

@ktutnik
Copy link
Member

ktutnik commented Feb 26, 2016

I made an investigation and i think it can be implemented

I am thinking of the interceptor will be a simple callback that passed on registration. should be able to apply multiple interception (with fluent binding interface will implemented nicely):

kernel.bind(new TypeBinding<IMyType>("IMyType", MyType, (invocation, container) => {
  if(invocation.methodName == "sayHelo"){
      //do interception bleh bleh

      //get other dependent Types
      var dependent = container.resolve<IOtherType>();
      //bleh bleh 

      //proceed invocation
      invocation.proceed();
  }
}));

invocation should consist of:

  • method name
  • method arguments
  • proceed function (without parameters)

Proxy Class
to support those feature, it is required to create a proxy class on the fly. In javascript the process is real easy using Object.getOwnPropertyDescriptor and Object.create

@remojansen
Copy link
Member

👍 We need to do some thinking about it but sound like a good idea to me.

@remojansen
Copy link
Member

Hi @ktutnik I'm doing some analysis on this week... can you please send me some documentation from an IoC where this is available? I would like to see theirs APIs and some real world use cases. Thanks 😄

@remojansen
Copy link
Member

Hi I've been reading about interception in Unity and Windsor Castle and I think what you are asking for in your example is not really interception as InversifyJS is not creating a proxy of the dependency being injected.

If you could please let me know what do you have in mind about this feature I will be happy to see if I can implement it but I have another feature in mind (middleware) that could be what you are looking for and is more powerful.

@remojansen remojansen removed this from the 2.0.0-alpha.2 milestone Mar 7, 2016
@ktutnik
Copy link
Member Author

ktutnik commented Mar 8, 2016

Yes interceptor is one step ahead.
Interception increase the separation concern. Because it give ability to change method/property behaviour from other location. So that behaviour is reusable among classes.
Example of interception, is adding caching behaviour to existing object without have to change the object itself.

I saw the middleware feature of Inversify but I think it will be different. middleware seems a global way to change the behaviour of the Iversify system. but interception is specific to class that registered to the container. User freely intercept which class and define them in the registration.

I made a dynamic proxy for this purposes. please take a look at https://github.com/ktutnik/benalu

@ktutnik
Copy link
Member Author

ktutnik commented Mar 8, 2016

@ktutnik
Copy link
Member Author

ktutnik commented Mar 8, 2016

here is example what it will be:
the purpose is showing a log of execution time of a method call and print it using console.time and console.timeEnd.

interface IKatana {
   swing();
}
class Katana implement IKatana {
   swing(){
      console.log('Swing performed');
   }
}

registration:

let kernel = new Kernel();
kernel.bin<IKatana>("IKatana").to(Katana).addInterception((invocation, context) => {
   if(invocation.memberName == "swing"){
      console.time();
      invocation.proceed();
      console.log("Katana.swing execution time");
      console.timeEnd();
   }
});

uses:

var katana = kernel.get<IKatana>("IKatana");
katana.swing();

the result will be:

Swing performed
Katana.swing execution time
9ms

@remojansen
Copy link
Member

Hi @ktutnik thanks for your help :) I think I understand it now. I have a few things in mind. One of my main concerns is introducing dependencies.

At the moment, we don't have dependencies (only polyfills for Promise and Reflect) so looks like is a good idea to do the same and use the Proxy. If the environment don't support Proxy we will use a polyfill.

I can imagine something like the following working:

interface IBindingProxySyntax<T> {
   proxy(fn: (injectable: T) => IProxy<T>);
}
kernel.bin<IKatana>("IKatana").to(Katana).proxy((katana) => {
   let handler = {
     // interception logic goes here... http://mzl.la/1UayLPy
   };
   return new Proxy(katana, handler);
});

What are your thoughts?

p.s. a good resource.

@ktutnik
Copy link
Member Author

ktutnik commented Mar 9, 2016

I think Proxy is not clearly made for interception. The key point of interception is the execution step (befor execution, after execution or both). User even can choose to not to execute the original method at all.
Proxy still can solve the problem but lost the feel of interception.

@remojansen
Copy link
Member

Please take a look to the following:

kernel.bin<INinja>("INinja").to(Ninja).proxy((ninja) => {
   let handler = {
        apply: function(target, thisArgument, argumentsList) {
           if(target.name === "swing") {
             console.time();
             let result = target.apply(thisArgument, args);
             console.log("swing execution time");
             console.timeEnd();
             return result;
           }
           else {
             return target.apply(thisArgument, args);
           }
        }
   };
   return new Proxy(ninja, handler);
});

We can achieve the same but we will be using standards.

@remojansen remojansen mentioned this issue Mar 10, 2016
11 tasks
@remojansen
Copy link
Member

Interception is now implemented in 2.0.0-alpha.3 but cannot be tested due to an issue with gulp-mocha and the --harmony-proxies flag. I'm going to create an issue for that issue, link it to to this and close this one.

@dtbiedrzycki
Copy link

dtbiedrzycki commented Dec 11, 2018

Was this work completed? I am on inversifyjs version 5.0.1 and do not see anything that seems to support this.

EDIT: found it!: https://github.com/inversify/InversifyJS/blob/master/wiki/activation_handler.md

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants