AsyncTimeout acts differently

Topics: ASP.NET MVC
Jun 2, 2012 at 1:53 PM

I am not sure if I get the usage of the AsyncTimeout action filter right. Here is my code:

    public class HomeController : Controller {

        [AsyncTimeout(50)]
        [HandleError(ExceptionType = typeof(TimeoutException), View = "TimeoutError")]
        public async Task<ActionResult> Foo() {

            using (HttpClient client = new HttpClient()) {
                ViewBag.Status = await client.GetStringAsync("http://localhost:2098/Home/Wait");
            }

            return View();
        }

        public string Wait() {

            Thread.Sleep(3000);
            return "Foo";
        }
    }

The web request took at least 3 seconds to complete as you can see that I am hanging the thread. So, I should get a timeout exception when I hit the /Home/Foo (at least this is what I understood from AsyncTimeoutAttribute) but request completes successfully every time.

I tried this with ASP.NET MVC 4 RC.

Jun 2, 2012 at 7:08 PM

For Task-returning methods, the attribute controls only the delay period of the CancellationToken that is passed into the action method. For more information about cancellation of Tasks see [1]

Henrik

[1] http://msdn.microsoft.com/en-us/library/dd997396.aspx

Jun 2, 2012 at 7:38 PM

Ok, now that makes all sense. It should have been something like following:

        [AsyncTimeout(1000)]
        [HandleError(ExceptionType = typeof(TimeoutException), View = "TimeoutError")]
        public async Task<ActionResult> Foo(CancellationToken cancellationToken) {

            using (HttpClient client = new HttpClient()) {
                await client.GetAsync("http://localhost:2098/Home/Wait", cancellationToken);
            }

            return View();
        }

Jun 2, 2012 at 8:41 PM
Edited Jun 2, 2012 at 8:42 PM

BTW, is there any specific reason why HttpClient.GetStringAsync method doesn't accept CancellationToken? It is not hard to provide it as extension method but I thought you guys would unless there is a specific reason.

Jun 2, 2012 at 9:04 PM

The way to cancel HTTP requests is to cancel them on the HttpClient directly. The reason being that multiple requests can reuse TCP connections within a single HttpClient and so you can't safely cancel a single request without possibly affecting other requests as well.

You can control the timeout for requests -- I think it's on the HttpClientHandler if I recall correctly.

Hope this helps,

Henrik

Jun 2, 2012 at 9:27 PM
Edited Jun 2, 2012 at 9:27 PM

Thanks for the information Henrik. But GetAsync has an overload method which accepts a CancellationToken. on the other hand, only specific ones don't have that such as GetStringAsync and GetStreamAsync. 

I played with a bit and modified the original code a bit. Here are the extension methods: https://gist.github.com/2859825 Is that something worth keeping it around?

Also, providing a Timeout value for the request achieves the goal as you suggested.