Kevin
Kevin

Reputation: 15934

How can I give a WCF service more time to complete after it times out?

We have a long-running asynchronous WCF service operation that grabs log files from the different components in our service. Right now, everything works correctly, but there's one more "nice to have" feature we'd like to implement.

WCF will time out asynchronous services if they take too long, but if one of our components is misbehaving, it could take a longer to give out its log file than we allot for the timeout period. If this happens, it would be nice if the client application told the user that getting log files was taking a while and asked if the user wanted to keep on waiting. If the user says yes, is there some way to resume the operation in the state it was when it timed out and reset the timeout timer?

This psuedocode shows what we have in mind:

public void GetServiceLogFiles(Action<Object> callback)
{
    try
    {
        var gotLogFilesDelegate = (result) =>
            { var answer = WcfService.EndGetLogFiles(result);
              callback(answer); };
        WcfService.BeginGetLogFiles(gotLogFilesDelegate, null);
    }
    catch(TimeoutException)
    {
        var dialog = new Dialog("The service is taking a while to get the log files. Would you like to keep on waiting for it to finish?");
        if(dialog.response = Dialog.YES)
            Magic_happens_here_and_lets_the_Wcf_Service_continue_working_on_Get_Log_Files();
    }
}

Upvotes: 0

Views: 412

Answers (1)

James
James

Reputation: 2841

There is a way to set the timeout values. Take a look at System.ServiceModel.Channels.Binding, which has the following properties:

ReceiveTimeout
OpenTimeout
SendTimeout
CloseTimeout

These can be set when creating a service proxy.

public static class MyWcfServiceProxyFactory
{
    public static MyWcfService CreateMyWcfService(string endpointUrl) 
    {

        EndpointAddress endpointAddress = new EndpointAddress(endpointUrl);
        CustomBinding customBinding = new CustomBinding();

        TimeSpan timeout = new TimeSpan(0, 5, 0);

        customBinding.ReceiveTimeout = timeout;
        customBinding.OpenTimeout = timeout;
        customBinding.SendTimeout = timeout;
        customBinding.CloseTimeout = timeout;

        ChannelFactory<MyWcfService> channelFactory = new ChannelFactory<MyWcfService>(customBinding, endpointAddress);

        return channelFactory.CreateChannel();
    }
}

The same settings are available if the binding is creating in config.

<bindings>
    <basicHttpBinding>
        <binding name="MyWcfService"  
        receiveTimeout="0:05:00"
        openTimeout="0:05:00"
        sendTimeout="0:05:00"
        closeTimeout="0:05:00">

I do not think the timeout can be changed after the fact, so you will have to create 2 channels, one with the "normal" timeout, and one with an extended timeout. If the normal one times out, the retry attempt can use the channel with the extended timeout.

Upvotes: 3

Related Questions