NInject problem with remote proxies

I have run into following issue while working with NInject:

System.TypeInitializationException: The type initializer for 'ClassA' threw an exception. --->    
System.Runtime.Remoting.RemotingException: Attempted to call a method declared on type 'Ninject.IInitializable' on an object which exposes 'ClassB'.
Server stack trace:
  at System.Runtime.Remoting.Messaging.StackBuilderSink.VerifyIsOkToCallMethod(Object server, IMethodMessage msg)
  at System.Runtime.Remoting.Messaging.StackBuilderSink.SyncProcessMessage(IMessage msg)

Exception rethrown at [0]: 
  at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
  at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
  at Ninject.IInitializable.Initialize()
  at Ninject.Activation.Strategies.InitializableStrategy.b__0(IInitializable x) in InitializableStrategy.cs:line 28

The problem is that NInject tries to call Ninject.IInitializable.Initialize() on remoting proxy (ClassB) and that fails since that class does not implement that interface. This call is made by one of the activation strategies in the pipeline.

The workaround is (inspired by Ydie’s blog post) to create new kernel class derived StandardKernel, remove all instances of IActivationStrategy from Components collection, return some of the default strategies back and add my own strategy that does not try to invoke Initialize method when the object being activated is instance of MarshalByRef class.

I don’t have any class implementing IStartable interface, so I’m not re-adding the StartableStrategy, but for complete fix that strategy should also be modified. Or the pipeline can be changed to completely ignore remoting proxies …

public class MyStandardKernel : StandardKernel
{
    protected override void AddComponents()
    {
        base.AddComponents();
        // remove the all activation strategies
        Components.RemoveAll(typeof(IActivationStrategy));
        // add some of the default strategies back (code copied from NInject sources)
        if(!Settings.ActivationCacheDisabled)
        {
            Components.Add<IActivationStrategy, ActivationCacheStrategy>();
        }

        Components.Add<IActivationStrategy, PropertyInjectionStrategy>();
        Components.Add<IActivationStrategy, MethodInjectionStrategy>();
        // I don't need this
        // Components.Add<IActivationStrategy, StartableStrategy>();
        Components.Add<IActivationStrategy, BindingActionStrategy>();
        Components.Add<IActivationStrategy, DisposableStrategy>();
        // this is the new strategy
        Components.Add<IActivationStrategy, RemotingProxyAwareStrategy>();
    }
}

public class RemotingProxyAwareInitializableStrategy : ActivationStrategy
{
    /// <summary>
    /// Initializes the specified instance.
    /// </summary>
    /// <param name="context">The context.
    /// <param name="reference">A reference to the instance being activated.
    public override void Activate(IContext context, InstanceReference reference)
    {
        if(reference.Is<MarshalByRefObject>()) 
        {
            return;
        }

        reference.IfInstanceIs<IInitializable>(x => x.Initialize());
    }
}

NInject modularity let’s you to replace different core components and that’s really great. I’m looking forward to another problem 🙂

One thought on “NInject problem with remote proxies

Leave a Reply to Risma Cancel reply

Your email address will not be published. Required fields are marked *

Blue Captcha Image
Refresh

*