1

So I'm writing a console app that calls a WCF service (via nettcpbinding) - and the business wants to be able to specify a value to use as the timeout value. I originally tried operation timeout but that seemed to get ignored - so I tried a bunch of other values. One of those works (or combination of) :)

I was hoping I could still close the channel if it times out - but if I put the closing in the finally block then it sits for another minute until it times out (whereas I'm setting a timeout value in seconds). I'm testing by adding a delay in the server side code - to simulate it taking awhile.

I can move the close to the first try block but I'm then concerned that I'll be leaving channels open. It then will report back the timeout error to the user a lot quicker. Or do I need to implement threading?

public static String ExecuteSearch(List<KeyValuePair<string, string>> paramItems)
{
    var context = GetAdminContext();
    var parsedParameters = ParseParameters((paramItems));

    //TODO: Figure out how to implement timeout - & workout if port number will be passed in?? 
    IPartyProfile partyProfile = null;

    long start = System.Environment.TickCount;

    using (ChannelFactory<IPartyController> factory = new ChannelFactory<IPartyController>("IPartyControllerEndpoint"))
    {
        EndpointAddress address = new EndpointAddress(String.Format("net.tcp://{0}/ServiceInterface/PartyController.svc", parsedParameters.HostName));
        IPartyController proxy = factory.CreateChannel(address);

        if (proxy != null)
        {
            var timeoutTimeSpan = new TimeSpan(0, 0, parsedParameters.TimeOut);
            ((IContextChannel)proxy).OperationTimeout = timeoutTimeSpan;
            factory.Endpoint.Binding.SendTimeout = timeoutTimeSpan;
            factory.Endpoint.Binding.ReceiveTimeout = timeoutTimeSpan;
            factory.Endpoint.Binding.OpenTimeout = timeoutTimeSpan;
            factory.Endpoint.Binding.CloseTimeout = timeoutTimeSpan;

            try
            {
                // TODO: potentially call something more complex
                partyProfile = proxy.GetLatestPartyProfile(context, parsedParameters.PartyId);

            }
            catch (EndpointNotFoundException ex)
            {
                throw new Exception(STATUS_UNKNOWN + ": Endpoint specified not responding", ex);
            }
            catch (TimeoutException ex)
            {
                throw new Exception(STATUS_UNKNOWN + ": Timeout exceeded", ex);
            }
            finally
            {
                try
                {
                    ((IClientChannel)proxy).Close();
                }
                catch (Exception)
                {
                }

            }
        }
    }

    long stop = System.Environment.TickCount;
    long elapsed = (stop - start) / 1000; // in seconds

    return SetResultMessage(elapsed, partyProfile, parsedParameters);
}

Edit - I think I can use factory.Abort() to end it quicker. (I'd put it where the Close is in the above code).

Druid
  • 6,423
  • 4
  • 41
  • 56
Jen
  • 1,964
  • 9
  • 33
  • 59
  • So I changed the order of where I was setting the timeouts and it seemed ok with just the SendTimeout value being specified. I also on the finally of my try catch - check if the channel is open and if so - abort the factory and call close. Doesn't seem to take forever anymore. – Jen Sep 20 '12 at 04:01

1 Answers1

1

From your description, SendTimeout is exactly the value you want to tweak (see also this question on various timeouts). It's 1 minute by default, but if you change it to something less (e.g. 5 seconds) calling proxy.GetLatestPartyProfile should indeed throw a TimeoutException after 5 seconds (assuming the service call is taking more than that to respond).

In the code you currently posted I can see at least one thing that may be causing your problems: you are setting the timeout value on the factory after you've already created the proxy. Reorder the relevant statements and retry. Something like this:

using (ChannelFactory<IPartyController> factory = new ChannelFactory<IPartyController>("IPartyControllerEndpoint"))
{
    var timeoutTimeSpan = new TimeSpan(0, 0, parsedParameters.TimeOut);
    factory.Endpoint.Binding.SendTimeout = timeoutTimeSpan;

    EndpointAddress address = new EndpointAddress(String.Format("net.tcp://{0}/ServiceInterface/PartyController.svc", parsedParameters.HostName));
    IPartyController proxy = factory.CreateChannel(address);

    if (proxy != null)
    {
        try
        {
            // TODO: potentially call something more complex
            partyProfile = proxy.GetLatestPartyProfile(context, parsedParameters.PartyId);
        }
        // etc.

Note: I'm not entirely sure what your current overload voor CreateChannel uses for a binding. Seems plausible that it uses the binding you set earlier, but if you are still having trouble you may experiment by using the CreateChannel(Binding, EndpointAddress) overload.

Community
  • 1
  • 1
Jeroen
  • 60,696
  • 40
  • 206
  • 339