03 September 2009

WCF Timeouts

Did you ever search all over the web and only find the same wrong answer, over and over? I recently had this experience.

In an unrelated project, I was trying to set up a notification system using WCF. At some unspecified point in time, the web service would receive a notification for the client and would need a way to propagate that notification. Our thought had been to implement this with asynchronous calls to the service.

When using Visual Studio's very handy WCF creation environment, immediately after building your WCF app you can have another project in the same solution discover it. The client project can then choose to implement the WCF service function calls "asynchronously" (this is a checkbox in the configuration dialog for adding/changing a service reference).

Now, let's get this straight once and for all: the call to the service is NOT asynchronous. When you add in the asynchronous operations, what ACTUALLY happens is that the generated client class creates a new thread to handle the call, then has that thread notify your main thread when the call returns, so that the function call is asynchronous to your client program. But the actual call to the server is synchronous and will time out in a minute. Let me stress, in ONE minute.

The default operation timeout on a WCF client channel is 00:01:00. And contrary to popular misinformation, the settings in your .config file have nothing to do with this. The error message itself includes this line:

Please consider increasing the operation timeout (by casting the channel/proxy to IContextChannel and setting the OperationTimeout property)

That being the case, your "asynchronous" call has exactly a minute to be notified and return with the goods, or you are catching an exception. How to increase the operation timeout? By casting the channel to IContextChannel.

I admit that though my reading comprehension skills are at least average, I missed the tip in the error message and wasted hours playing with .config files, just as the forums suggested. Until I found this:

http://www.codeproject.com/KB/WCF/WCF_Operation_Timeout_.aspx

Yes, the error message had it right.

Since we're working with the autogenerated client class, it would be unwise to go into the (hidden) Reference.cs file that contains the ServiceClientFoo class. Note, however, that ServiceClientFoo is a partial class. So we can make our own file, call it ServiceClientFoo.cs, and open the class from there:


    public partial class ServiceFooClient : System.ServiceModel.ClientBase<CurrNamespace.ServiceFooRef.IServiceFoo>, CurrNamespace.ServiceFooRef.IServiceFoo
    {
        public IServiceFoo SetOpTimeout(TimeSpan timeout)
        {
            ((IContextChannel)base.Channel).OperationTimeout = timeout;
        }
    }

4 comments:

  1. Thank you! This was maddening until I found your post!

    ReplyDelete
  2. Your SetOpTimeout method has a return type but no return value. Can you explain your intent here? Should the method return void? Thanks for the tip, in any case.

    ReplyDelete
  3. fyi:

    var myService = new ServiceClient(...);
    myService.InnerChannel.OperationTimeout = new TimeSpan(....);

    OperationTimeout is used to init the other timeouts, from what i read they can also be set in the .config though i personally never required different values or that much control

    ReplyDelete
  4. Hi Golda!
    Thank you for your post, I have been struggling with this problem for a while now and your answer seems to maybe solve the problem. However when I cast the channel to IContextChannel my program continues to wait for service and does not do anything. Got any ideas why it does that?

    ReplyDelete