WCF on TCP : Keep your connections alive
I recently had a customer coming in with question and request on WCF connection pooling, which is very valid. I was almost convinced that answer to his question would be 'by design' but what worried me was if there is a solution for his predicament. To my pleasant surprise, mighty WCF team did think about the scenario and 'by design' there was a solution to his exact problem.
He is using net.tcp port sharing on the server for two different WCF services configured with net.tcp binding. The client code is such that proxy is created every time, service called and proxy closed. This sequence could be done for two services in any required combinations, lets say by calling Service 1() and Service2(). If Service1() is called repeatedly, TCP connection created in first call is pooled and reused. This is nice and as expected to save on connection establishment costs every time. But as soon as Service2() is called, TCP connection used for Service1() is reset. This sounds inappropriate. Seems, cost of port sharing is that pooled connection for Service1 has to be replaced with new connection to Service2. Very inefficient in an enterprise scenario where client makes random calls to Service1 and Service2 in volume as connection will be reset each time.
Whoever plays with TCP connection pooling is almost certain to stumble upon this: https://kennyw.com/work/indigo/173
Solution to my customer's predicament lies in this line taken from above link "Our connection pool is configurable through TcpConnectionPoolSettings/NamedPipeConnectionPoolSettings . These settings include a GroupName that we use for isolation"
You may think of it like this. TCP connection pool in WCF is identified with 'Port Number' and 'GroupName' (possibly more but only these are relevant for our purpose). If you omit 'GroupName', WCF provides a default. If you are not explicitly providing 'connectioPoolSettings', you are in effect omitting 'GroupName'. Since both the endpoints (for Service1 and Service2) use same port and have same 'GroupName' (Default), implies both endpoints will use same connection pool Id. When Service2 needs to be reached, its connection pool is already in place at client side but WCF infrastructure need to reset the connection to same port.
Use 'GroupName' to isolate connection pools for two endpoints and you can have connections alive when switching from Service1 to Service2 in there own respective pools.
This does mean that you will need to resort to custom binding but that’s an acceptable cost for such a huge benefit. A typical client config to achieve desired behaviour with net.tcp transport will look like this:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<bindings>
<customBinding>
<binding name = "bindingA">
<tcpTransport>
<connectionPoolSettings groupName="connectionPoolA"/>
</tcpTransport>
</binding>
<binding name ="bindingB">
<tcpTransport>
<connectionPoolSettings groupName="connectionPoolB" />
</tcpTransport>
</customBinding>
</bindings>
</binding>
<client>
<endpoint address="net.tcp://<hostname>/<APPLICATION-A>/Service.svc"
binding="customBinding" bindingConfiguration="bindingA"
contract="WCF1.IService" name="NetTcpBinding_IService_A">
</endpoint>
<endpoint address="net.tcp://<hostname>/<APPLICATION-B>/Service.svc"
binding="customBinding" bindingConfiguration="bindingB"
contract="WCF2.IService" name="NetTcpBinding_IService_B">
</endpoint>
</client>
</system.serviceModel>
</configuration>
Comments
- Anonymous
June 14, 2012
Interesting article , but i think that, before being able to understand it in a full way , i will have to study WCF in a deep way ( i am seeing the connections problems mainly thru SQL Server Data Access ) Anyway , i have added not only your post but the included links in my favorites and , before forgeting , many thanks