Problem description
Sometimes you will have to connect to some other service while executing of some service method in your service. Following example shows the method “TestMethod”, which performs this action. When the consumer invokes the operation Operation1(), the operation creates the new proxy instance on each call. For the sake of simplicity this code does not perform any action on created channel instance.
When you do this the service code will do leaking as Steve has noticed in this post. Not that leaking happens only if instance context mode is set on Single.
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public void Operation1()
{
BasicHttpBinding b2 = new BasicHttpBinding();
ChannelFactory<ISomeOtherService> fx = new ChannelFactory<ISomeOtherService>(b2, "http://localhost:51234/Test2");
ISomeOtherService proxy = fx.CreateChannel();
((IChannel)proxy).Close();
((IDisposable)proxy).Dispose();
}
Here is the related host sample.
ServiceHost host = new ServiceHost(typeof(MyService), new Uri("http://localhost:51234/Test"));
host.AddServiceEndpoint(typeof(IMyService), new BasicHttpBinding(), "");
host.Open();
Workaround:
First it is important to know that leaking-issue will happen in all bindings. That means it is not a WCF-bug in some specific binding. Note also, that the trivial code in Operation1 does not produce leak at all. You can prove this if you copy the code in some other none-WCF method and execute it in endless loop. You will notice that there is no leak.
So, if all works fine, how it is possible that the code above produce leaks? The answer is deep down in WCF part called OperationContext.
The code shown above will produce leaks only if the operation context exists. When this is case and when not is out of scope of this post (For example if security is totally disabled operation context is null).
When the channel is created and the operation context exists, then each new channel instance is appended in the list of WmiChannels (see property InstanceContext.WmiChannels in code below). This list causes the leak. However if the InstanceContext is recreated on each invoke of operation (that is when InstanceContextMode is set on PerCall), the list will be recreated and no leak will be caused.
Here is s short snapshoot of WCF factory CreateChannel code:
public object CreateChannel()
{
serviceChannel = …
. . .
OperationContext current = OperationContext.Current;
if ((current != null) && (current.InstanceContext != null))
{
current.InstanceContext.WmiChannels.Add((IChannel)serviceChannel.Proxy);
serviceChannel.WmiInstanceContext = current.InstanceContext;
}
return serviceChannel.Proxy;
}
So, we could now discuss about this behavior trying to declare it as design issue of WCF or even let it as it is. Please let me know what you think.
However, solution for this issue could be and is to create proxy instances for one destination only once and store them internally in some member. Assuming that the InstanceContext is set on “Single” means that the service instance is singleton. If this holds, then also proxy instances can be singletons too. If not, then one could ask, “why the service should be singleton at all”?
Damir
Posted
Mar 31 2009, 12:00 PM
by
Damir Dobric