12

I'm new to asp.net 4.5 async and am running into the following with calling response.redirect within an async method. The issue is that the response just "hangs" Has anyone else experienced similar issues with attempting an redirect with async? This code will work in a brand new project, but, does not work with a new page in our existing code. I made sure to gut out everything I could out of our web.config and removed our master page. Hitting a brick wall...any ideas? Thanks!

    protected void Page_Load(object sender, EventArgs e)
    {
        RegisterAsyncTask(new PageAsyncTask(PageLoadAsync));
    }

    private async Task PageLoadAsync()
    {
        var data = await GetData();

        if (data == HttpStatusCode.OK)
            Response.Redirect("http://www.google.com");
    }

    private async Task<HttpStatusCode> GetData()
    {
        using (var client = new HttpClient())
        {
            var response = await client.GetAsync("https://www.google.com");
            return response.StatusCode;
        }
    }
newman
  • 123
  • 1
  • 1
  • 4
  • 1
    I dont think you can execute `Redirect` on async thread – Murali Murugesan Nov 22 '13 at 14:56
  • I don't see why you need async, you still need to wait for the HttpClient to respond before finishing loading/rendering the page. And you aren't doing multiple things at the same time. btw: if you have internet connection, google will always work ;) – the_lotus Nov 22 '13 at 14:59
  • 3
    He needs async because he is doing an I/O intensive task (sending an HTTP request to a remote resource). Imagine that this resource takes long time to respond. You will be jeopardizing your ASP.NET worker thread during this time. Now imagine that this endpoint is hit by 200 users at the same time => your site will die because there won't be any worker threads available to service the requests. That's why it is extremely important to use async in this case. – Darin Dimitrov Nov 22 '13 at 15:05
  • @DarinDimitrov, how the worker thread will get the response? or server will push the update(chunks) to client like HTML5 websockets? I still in confusion `how RegisterAsyncTask works?` – Murali Murugesan Nov 22 '13 at 15:10
  • 1
    The client.GetAsync method uses an I/O Completion Port. You can read more about them here: http://msdn.microsoft.com/en-us/magazine/cc163463.aspx. There are no chunks or HTML5 WebSockets in server to server communication. – Darin Dimitrov Nov 22 '13 at 15:35
  • @MuraliMurugesan there is no such thing as an "async thread" – sara May 13 '16 at 08:43

2 Answers2

27

This code will work in a brand new project, but, does not work with a new page in our existing code.

I assume your existing site has already been upgraded to .NET 4.5.

The first thing to check is that httpRuntime.targetFramework is set to 4.5. This is not set by default when you upgrade.

Edit from comments:

Another thing to check (just in case) is that Page.Async is set to true.

In this case, the solution was to call Response.Redirect("http://www.google.com", false), which explicitly passes false for the endResponse parameter. The default value of true is only for backwards-compatibility reasons as described here.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • Good point. Our project is 4.5 and the targetFramework is 4.5 in our config. We have implemented async in ten or so pages now and it is working. The issue is that two of our pages need to perform a redirect after an async call on the same response. Trying to figure out the differences right now between the test project and our project. Appreciate the response. – newman Nov 22 '13 at 16:23
  • I almost hate to ask this, but you do have `Page.Async` set to `true`, right? – Stephen Cleary Nov 22 '13 at 16:58
  • Another valid question. Yes, I do. – newman Nov 22 '13 at 18:47
  • No.. I didn't. For some reason, I had it in my brain that false was the default and I tried it with true at one point.. I've implemented it one of our live pages and that seems to be happy too. Sometimes the simplest things are the easiest to overlook. Thanks a bunch! I'll mark your answer as correct. – newman Nov 22 '13 at 21:22
  • Stephen, that link you provided is returning a 403. Do you happen to have an updated link to the same article? – julealgon Mar 27 '23 at 21:49
  • 1
    @julealgon: Yeah, MS broke all their links a few years ago. Really annoying. Should be fixed now. – Stephen Cleary Mar 27 '23 at 22:33
  • Current HttpConext getting null in my case! So, Response generating object reference error! – Khalid Bin Sarower Jul 23 '23 at 11:57
  • @KhalidBinSarower: please post your own question with reproducible code. – Stephen Cleary Jul 23 '23 at 12:57
0

The hack I used is:

  1. I used a static dictionary as var d= new Dictionary<string, bool>(); in the class where my API calling method is written.

  2. I put the code line client.timeout = new System.TimeSpan(0,0,60); for API sending the request.

  3. When API is timed out, it throws the TaskTimeoutException, in the TaskTimeoutExceptioncatch block write code as d.Add("timeout", true);

  4. Now, I created the custom action filter and applied the following code:

    public class MyCustomActionFilter : ActionFilterAttribute
    {
        public override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            if(MyApiClass.d.ContainsKey("timeout") && d["timeout"])
            {
                throw new Exception();
            }
        }
    }
    
  5. I applied the [MyCustomActionFilter ] on the action.

  6. When action is executed and enter the custom filter it throws Exception by checking the dictionary entry.

  7. If timeout would have occurred then dictionary entry will be true, so, on the basis of that, we check the entry and throws the exception. Now, we have Application_Error() in Global.asax.cs that catches the exception.

  8. In the Application_Error() we have written the code for redirect to the required page.

NOTE: In step 4 you can create your custom exception to provide more precise detail for logging.

Prashant Tomar
  • 209
  • 1
  • 11