Thursday, September 25, 2008

Singleton WCF Proxy

In WCF, creating a proxy is a heavy operation, so if you are experiencing performance slowdown you should definitely look at this area. One of the possible solutions to tackle this problem is to reuse your proxies across your application threads, either implementing a singleton or a pool, but in any case bear in mind that proxy reusability is only advisable in some scenarios (see this and this for the considerations).
Ok, so let's say that we want to go for a singleton proxy and we use Castle as a DI container to handle the proxy instances.
In theory the implementation would be as easy as this

<configuration>
<components>
<component id="TestService"
service="WCFTest.Contracts.ITestService, WCFTest.Contracts"
type="WCFTest.Proxies.TestProxy, WCFTest.Proxies"
lifestyle="singleton">
</component>
</components>
</configuration>
Where ITestService is the WCF contract and TestProxy is the proxy for that contract... End of the story? Not quite. The problem here arises when for any reason the channel associated to the proxy gets faulted. You probably already know that a faulted proxy can no longer connect to a service and in order to connect again to it there is no option than throwing away the faulted proxy instance and using a new one.
So it seems that the singleton approach doesn't suit our needs; we need to find a way of recreating proxy instances only when a proxy is in faulted state, something like this approach but fit in our DI container. Good news is that Castle gives the possibility to define custom lifestyle managers for our instances; we just need to implement the ILifestyleManager interface (or like in the following code snippet, the abstract class AbstractLifestyleManager) and provide the expected behavior.
/// <summary>
/// Singleton WCF Proxy Lifestyle Manager
/// </summary>
public class SingletonWCFProxyLifestyleManager : AbstractLifestyleManager
{
#region properties
private object instance;
#endregion

#region overriden methods

/// <summary>
/// Resolves the specified instance from the context.
/// </summary>
/// <param name="context">The context.</param>
/// <returns>The resolved object</returns>
public override object Resolve(Castle.MicroKernel.CreationContext context)
{
lock (base.ComponentActivator)
{
//If the instance does not exists it is resolved
if (this.instance == null)
{
this.instance = base.Resolve(context);
}
else
{
ICommunicationObject communicationObject = this.instance as ICommunicationObject;
//If the proxy is in faulted state, it's aborted and
//a new proxy is created
if (communicationObject != null &&
communicationObject.State == CommunicationState.Faulted)
{
try
{
communicationObject.Abort();
}
catch { }

this.instance = base.Resolve(context);
}
}
}
return this.instance;
}

/// <summary>
/// Releases unmanaged and - optionally - managed resources
/// </summary>
public override void Dispose()
{
if (this.instance != null)
{
base.Release(this.instance);
}
}

/// <summary>
/// Releases the specified instance.
/// </summary>
/// <param name="instance">The instance.</param>
public override void Release(object instance)
{

}
#endregion
}
Then we need to change the objects configuration file to use our custom implementation.
<configuration>
<components>
<component id="TestService"
service="WCFTest.Contracts.ITestService, WCFTest.Contracts"
type="WCFTest.Proxies.TestProxy, WCFTest.Proxies"
lifestyle="custom"
customLifestyleType="WCFTest.Common.SingletonWCFProxyLifestyleManager, WCFTest.Common">
</component>
</components>
</configuration>
Well, I hope that if you are using Castle to manage singleton WCF proxies, this post will be helpful.

kick it on DotNetKicks.com

4 comments:

  1. Thanks Javi, excellent reference. I starred it in my feed reader in case I need it in future.

    ReplyDelete
  2. Great article, just what I was looking for!

    ReplyDelete
  3. Thanks, but how does this handle the case where client code has resolved the WCF proxy from the container, and then holds onto a reference to it? Won't the client code need to re-resolve the proxy from the container each time it needs it?

    ReplyDelete
  4. Nice piece of code. Can You show the same functionality but for the Unity container ?

    ReplyDelete