简体   繁体   中英

Implementing timeout for WCF service c# console app

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).

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 (eg 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM