Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.NET 4.5 async-await and Response.Redirect

Is there any way to redirect from Page_Load (or any other ASP.NET event) when using async-await? Of course Redirect throws ThreadAbortException but even if I catch it with try-catch it ends up with an error page. If I call Response("url", false) it doesn't crash but I need to stop execution of the page (rendering the page etc.) so it's not the solution. And as I noticed these two methods act differently:

This ends up with ThreadAbortException (I assume the task ends synchronously):

protected async void Page_Load()
{
    await Task.Run(() => { });
    Response.Redirect("http://www.google.com/");
}

This one continues after Response.Redirect:

protected async void Page_Load()
{
    await Task.Delay(1000);
    Response.Redirect("http://www.google.com/");
}

I must wait for the response but I was experimenting and even if I remove the await keyword (so Task runs in background and the method continues) it ends up the same. Only thing that helps is to remove the async keyword - I thought async ONLY enables await and nothing more?!

like image 451
JakubRi Avatar asked Oct 29 '12 16:10

JakubRi


2 Answers

OK, I found the answer how to deal with it.

I've created a Redirect method wrapper in my base Page class:

protected void Redirect(string url)
{
    this.isRedirecting = true;

    Response.Redirect(url, false);

    if (Context.ApplicationInstance != null)
        Context.ApplicationInstance.CompleteRequest();
}

And override Render and RaisePostBackEvent:

protected override void Render(HtmlTextWriter writer)
{
    if (this.isRedirecting)
        return;
}

protected override void RaisePostBackEvent(IPostBackEventHandler sourceControl, string eventArgument)
{
    if (!this.isRedirecting)
        base.RaisePostBackEvent(sourceControl, eventArgument);
}

That does the trick. ASP.NET 4.5 won't fire the PreRenderComplete event (= won't continue in the life-cycle) until all awaited tasks are completed.

like image 115
JakubRi Avatar answered Oct 11 '22 08:10

JakubRi


Diclaimer: I've not used async/await but the following is based on my reading of the docs.

As I understand it whenever you have an await in the code it will call the task provided aynchronously and the rest of the method is in effect converted into a callback method. So in this case because Page_Load is async when it runs it and it comes to an await it will return control to the caller while waiting for its aynchronous task to complete.

In the case of the Page_Load event this will, I think, then appear as if it has completed sopresumably the page life cycle will continue onto its next step.

The reason for the differences is that in your first example although it will continue on with the life cycle the callback is almost immediate so the Response.Redirect will run almost immediately, before the rest of the page has a chance to do anything.

In the case of the second one you have that delay of 1000 and during that time the page will continue running other things and its only when that delay is over that the respone.redirect fires. This might be after a response (from an error) has already been fired.

So in essence async does enable await but what await does sounds like it is a bit more than you expect.

like image 1
Chris Avatar answered Oct 11 '22 09:10

Chris