Best Practice: Always open WCF client proxy explicitly when it is shared
In order to provide symmetric programming model for the client-side as for the server-side, WCF leverages .NET Remoting transparent proxy technique so that the service contract interface can be used seamlessly as on the server-side. The svcutil.exe tool can generate WCF client proxy code for you. If you take a closer look at the generated code, you will find out that the proxy class is a subclass of ClientBase<T>. By using ChannelFactory<T>, you can create your proxy (or called channel) directly without going through ClientBase<T>.
Creating a WCF proxy is quite a heavy-weighted operation. So sometimes, you would want to create a single proxy and let multiple threads to use it. This works quite well if you don’t want the proxy to keep specific context (such as security credential) on each call.
The best practice in this case is that: you should always open WCF client proxy explicitly before you are making any calls. Here is the sample code if you use auto-generated proxy from svcutil.exe:
MyHelloServiceClient proxy = new MyHelloServiceClient();
proxy.Open();
// Make a call with the proxy
proxy.Hello("Hello world!");
Here is the sample code if you use ChannelFactory<T> to create a proxy:
ISimpleContract proxy = factory.CreateChannel();
((IClientChannel)proxy).Open();
// Make a call with the proxy
proxy.Hello("Hello world!");
If you don’t call the “Open” method first, the proxy would be opened internally when the first call is made on the proxy. This is called auto-open.
Why? When the first message is sent through the auto-opened proxy, it will cause the proxy to be opened automatically. You can use .NET Reflector to open the method System.ServiceModel.Channels.ServiceChannel.Call and see the following code:
if (!this.explicitlyOpened)
{
this.EnsureDisplayUI();
this.EnsureOpened(rpc.TimeoutHelper.RemainingTime());
}
When you drill down into EnsureOpened, you will see that it calls CallOnceManager.CallOnce. For non-first calls, you would hit SyncWait.Wait which waits for the first request to complete. This mechanism is to ensure that all requests wait for the proxy to be opened and it also ensures the correct execution order. Thus all requests are serialized into a single execution sequence until all requests are drained out from the queue. This is not a desired behavior in most cases.
To avoid such “serializing” artifact, the best practice is to open the proxy explicitly as above. Once you get to this point, you will be able to share the same proxy object among multiple threads.
Comments
Anonymous
October 25, 2007
PingBack from http://msdnrss.thecoderblogs.com/2007/10/26/best-practice-always-open-wcf-client-proxy-explicitly-when-it-is-shared/Anonymous
October 26, 2007
Introduction ASMX Proxy vs WCF Proxy ASMX proxy is much simpler than WCF proxy. The former is a wrapperAnonymous
October 26, 2007
Introduction In .NET 3.0 SP1, which will be shipped together with .NET 3.5, there is significant performanceAnonymous
October 28, 2007
The comment has been removedAnonymous
October 30, 2007
Introduction In .NET 3.0 SP1, which will be shipped together with .NET 3.5, there is significant performanceAnonymous
June 11, 2009
I remembered that MSDN said that all calls to the same proxy will be serialized/queued, so proxy should not be reused in concurrent request scenario. Am I wrong and it will work fine if Open() is explicitly called?Anonymous
November 19, 2015
I would like to emphasise this works for some scenarios, because it turns out that it depends on the binding you're using. When using the BasicHttpBinding it did work but when using the NetNamedPipe binding all calls were still synchronized.