none
Best pattern for async web requests with timeout handling

    Question

  • We need to put this together at short notice and any advice is appreciated as research time is very limited. We need to make async web requests to an external service from inside our own local REST MVC service. The request will either respond (easy part) or timeout, if it times out we must send a second CANCEL request and then we're done.

    Assume .Net Framework 4.6 and VS 2017 any supported version of C# language is fine, RestSharp is available too if this helps.

    I'd assumed this was trivial (and it may be!) but initial web search gives me the impression this isn't as straightforward as I'd hoped.

    Friday, January 11, 2019 2:28 PM

All replies

  • Depends upon the web request. If this is to a REST API call then you'll be using HttpClient which supports cancellation. If you're making an HTTP call via WebClient or similar it may be harder.

    Here's some untested code. There are other ways of doing it as well.

    class Program
    {
        static void Main ( string[] args )
        {
            //Create a cancellation source
            var cancellation = new CancellationTokenSource();
    
            //Start long running task (10 seconds)
            var task = LongRunningProcessAsync(10, cancellation.Token);
                
            //Wait for it to complete or 5 seconds
            if (!task.Wait(5000))
            {
                //Took too long so cancel it
                cancellation.Cancel();
            };
    
            //Task will be cancelled at some point hereafter
        }
    
        static Task LongRunningProcessAsync ( int count, CancellationToken cancellationToken )
        {
            return Task.Run(() => {
                for (var index = 0; index < count; ++index)
                {
                    Console.WriteLine(index);
                    Thread.Sleep(1000);
                };
            }, cancellationToken);
        }
    }
    Basically you start the request async. Then you wait for it to complete - note this is a blocking call. If it doesn't complete before your wait is done then you cancel it. If you need to do this unblocked then you can set up a timer to cancel the token after a given amount of time instead.


    Michael Taylor http://www.michaeltaylorp3.net

    Friday, January 11, 2019 3:57 PM
    Moderator
  • Depends upon the web request. If this is to a REST API call then you'll be using HttpClient which supports cancellation. If you're making an HTTP call via WebClient or similar it may be harder.

    Here's some untested code. There are other ways of doing it as well.

    class Program
    {
        static void Main ( string[] args )
        {
            //Create a cancellation source
            var cancellation = new CancellationTokenSource();
    
            //Start long running task (10 seconds)
            var task = LongRunningProcessAsync(10, cancellation.Token);
                
            //Wait for it to complete or 5 seconds
            if (!task.Wait(5000))
            {
                //Took too long so cancel it
                cancellation.Cancel();
            };
    
            //Task will be cancelled at some point hereafter
        }
    
        static Task LongRunningProcessAsync ( int count, CancellationToken cancellationToken )
        {
            return Task.Run(() => {
                for (var index = 0; index < count; ++index)
                {
                    Console.WriteLine(index);
                    Thread.Sleep(1000);
                };
            }, cancellationToken);
        }
    }
    Basically you start the request async. Then you wait for it to complete - note this is a blocking call. If it doesn't complete before your wait is done then you cancel it. If you need to do this unblocked then you can set up a timer to cancel the token after a given amount of time instead.


    Michael Taylor http://www.michaeltaylorp3.net

    Hi Mark,

    Thanks for this but can we do this 100% async? Is there a way to give the request itself a timeout so that it throws an exception?

    Friday, January 11, 2019 4:34 PM
  • CancellationTokenSource has a CancelAfter method you can use.

    static void Main ( string[] args )
    {
        //Create a cancellation source
        var cancellation = new CancellationTokenSource();
    
        //Start long running task (10 seconds)
        var task = LongRunningProcessAsync(10, cancellation.Token);
    
        cancellation.CancelAfter(5000);
    }
    Start your async task and then call CancelAfter to start the clock. After the interval expires the task is cancelled (but unless it is checking for cancellation it will still continue to run). In either case it isn't a blocking call so you can await on the task. It will either complete or cancel.


    Michael Taylor http://www.michaeltaylorp3.net

    Friday, January 11, 2019 5:49 PM
    Moderator
  • Hi Captain Kernel,

    Is there any update? do you try the method that CoolDadTx provided, if the issue still exists, please feel free let us know.
    Best regards,

    Jack

    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Wednesday, January 16, 2019 3:29 AM