Search code examples
c#externalevent-listener

C# add listener to external API property


I'm writing a plugin for a tool using the tool's plugin API. The API provides several callbacks for important events, like objects created or modified. However, unfortunately this API doesn't seem very consistent, so the event doesn't fire for some properties that I would need to listen to.

Is there a way to react to methods of external API classes being called without direct code access? I know that classes can be extended, but I'm not aware of altering existing properties. Also the API classes are sealed and methods are not virtual, so no way of overriding.

The API is closed-source, so nothing else I can do here really. The developers don't seem to be supporting their API anymore, so there's little hope for them to implement these changes, so I have to look for workarounds. I would be glad for any kind of example on how to accomplish this, if at all possible.

Example of pseudo-code on what I would like to accomplish:

public class ApiClass // the class I have no code access to but is exposed via the API
{
     public void SomeMethod() {  } // this method is called via the tool's interface, this event I want to hook into
}

public class MyClass // my code
{
    private MethodListener myMethodListener = new MethodListener();

    public void init(ApiClass obj)
    {
        myMethodListener.register(obj.SomeMethod, MyCallback)
    }

    public void MyCallback() 
    {
        // some stuff I want to do after the tool called SomeMethod()
    }
}

So whenever the tool itself internally calls it's SomeMethod() I want to be executing my own code. I do not wish to alter the original methods arguments or return values or flow of execution, I simply want to react to it being called.

One possibility would propably be decompiling the API assembly, modify it and recompile to use in my plugin, but I would rather want to avoid that.


Solution

  • I found this article which describes crating a dynamic proxy to wrap an object instance and intercept method calls, then forwarding them on with DynamicObject.TryInvokeMember.

    There a bunch of downsides to that such as the object being Dynamic so intellisense goes out the window, and it invokes everything via reflection which has an overhead.

    But if it digs you out of a hole...