I am stumped. Perhaps someone can shed some light on WCF client behavior I am observing.
Using the WCF samples, I've started playing with different approaches to WCF client/server communication. While executing 1M of test requests in parallel, I was using SysInternals TcpView to monitor open ports. Now, there are at least 4 different ways to call the client:
- Create the client, do your thing, and let GC collect it
- Create the client in a using block, than do your thing
- Create the client channel from factory in a using block, than do your thing
- Create the client or channel, but use WCF Extensions to do your thing
Now, to my knowledge, only options 2-4, explicitly call client.Close(). During their execution I see a lot of ports left in the TIME_WAIT state. I'd expect option 1 to be the worst case scenario, due to reliance on the GC. However, to my surprise, it seems to be the cleanest of them all, meaning, it leaves no lingering ports behind.
What am I missing?
UPDATE: Source code
private static void RunClientWorse(ConcurrentBag<double> cb)
{
var client = new CalculatorClient();
client.Endpoint.Address = new EndpointAddress("net.tcp://localhost:8000/ServiceModelSamples/service");
RunClientCommon(cb, client);
}
private static void RunClientBetter(ConcurrentBag<double> cb)
{
using (var client = new CalculatorClient())
{
client.Endpoint.Address = new EndpointAddress("net.tcp://localhost:8000/ServiceModelSamples/service");
RunClientCommon(cb, client);
}
}
private static void RunClientBest(ConcurrentBag<double> cb)
{
const string Uri = "net.tcp://localhost:8000/ServiceModelSamples/service";
var address = new EndpointAddress(Uri);
//var binding = new NetTcpBinding("netTcpBinding_ICalculator");
using (var factory = new ChannelFactory<ICalculator>("netTcpBinding_ICalculator",address))
{
ICalculator client = factory.CreateChannel();
((IContextChannel)client).OperationTimeout = TimeSpan.FromSeconds(60);
RunClientCommon(cb, client);
}
}
private static void RunClientBestExt(ConcurrentBag<double> cb)
{
const string Uri = "net.tcp://localhost:8000/ServiceModelSamples/service";
var address = new EndpointAddress(Uri);
//var binding = new NetTcpBinding("netTcpBinding_ICalculator");
new ChannelFactory<ICalculator>("netTcpBinding_ICalculator", address).Using(
factory =>
{
ICalculator client = factory.CreateChannel();
((IContextChannel)client).OperationTimeout = TimeSpan.FromSeconds(60);
RunClientCommon(cb, client);
});
}