views:

563

answers:

2

I am looking for some info on using and configuring windsor to provide a dynamic proxy to intercept calls to an instance of another class.

My class represents a resource that should be retained as a long lived instance by the container for performance reasons. However, sometimes this resource can transition into ununusable state, and requires renewing. I would like the container to handle this so client code doesn't have to. I can create my own factory to do this, I would like to know if there is some Windsor registration coolness to do it for me so I don't have to create the separate factory class :)

Here is some pseudo code to demonstrate the problem:

public interface IVeryImportantResource
{
    void SomeOperation();
}

public class RealResource : IVeryImportantResource
{
    public bool Corrupt { get; set; }

    public void SomeOperation()
    {
        //do some real implementation
    }
}

public class RealResourceInterceptor : IInterceptor
{
    private readonly IKernel kernel;

    public RealResourceInterceptor(IKernel Kernel)
    {
        kernel = Kernel;
    }

    public void Intercept(IInvocation invocation)
    {
        RealResource resource = invocation.InvocationTarget as RealResource;

        if(resource.Corrupt)
        {
            //tidy up this instance, as it is corrupt
            kernel.ReleaseComponent(resource);
            RealResource newResource = kernel.Resolve<RealResource>(); //get a new one
            //now what i would like to happen is something like this
            //but this property has no setter, so this doesn't work
            //also, i would like to know how to register RealResourceInterceptor as well RealResourceInterceptor
            invocation.InvocationTarget = newResource;
        }
        invocation.Proceed();
    }
}

Any ideas how to implement something like my RealResourceInterceptor class, and also how to configure the container to use it? Thanks!

+1  A: 

This question is more about renewing a singleton component than interception. The problem of renewing singletons is answered in this question.

Bottom line: it's not as easy as it seems, there are many pitfalls with this approach.

Maybe the problem lies in this component getting corrupted (why does this happen?)

Mauricio Scheffer
Using the castle facility is the way forward
Noel Kennedy
A: 

My object is a WCF proxy. These objects will transition to a faulted state which makes them un-useable. I have no control over when or if they will transition. I can only detect it has happened, and recreate a new proxy.

Thanks for the link, the section quoted below describes roughly how I am currently doing it:

Alternatively another approach is to have a decorator for your service registered in the container with a singleton lifestyle, but your actual underlying service registered in the container with a transient lifestyle - then when you need to refresh the component just dispose of the transient underlying component held by the decorator and replace it with a freshly resolved instance (resolve it using the components key, rather then the service, to avoid getting the decorator) - this avoids issues with other singleton services (which aren't being "refreshed") from holding onto stale services which have been disposed of making them unusable, but does require a bit of casting etc. to make it work

My question is, instead of either of these:

1) using a statically typed decorator, to wrap my RealResource (as above). Once you get a number of these proxies, it becomes a pain having to create decorators for them all.

2) using a factory object which creates the dynamic proxy to manage the state of any WCF proxy.

2) is by far superiour but seems like something Windsor might already be able to do for me. So, I would like to know if is there any container automagic, which will allow me to register an interceptor at config time instead of creating my own factory?

Something like this pseudocode:

container.AddComponent("dynamicProxyWrapper", typeof(IRealResource), typeof(RealResource)).UsingInterceptor(typeof(RealResourceInterceptor));
Noel Kennedy
Have you tried the WCF facility? http://www.castleproject.org/container/facilities/trunk/wcf/index.html
Mauricio Scheffer