Using Response.Redirect Effectively

        Introduction:


                    I was reviewing an ASP.NET Web Form application which has some scalability issues. Means, the application was becoming slow when the traffic on the site increases. When I check the application logs, I have found a huge amount of ThreadAbortException. The application was heavily using Response.Redirect(yes with endResponse= true), which was the root cause of scalability issue. Passing endResponse = false in Response.Redirect will solve this issue. But doing so causes the application behaves very strangely because the application was assuming that Response.Redirect will stop the current page execution. In addition, there are some security risks you need to handle because your application was assuming that the page events will never execute after redirect. In this article, I will tell you an easy way to tackle these problems and gain good performance.


        Description:

 

 

                    Let's say you have a web form which check some condition and redirect the user when the condition does not meet,


        
        protected void Page_Load(object sender, EventArgs e)
        {
            var condition = ......;
            if (!condition)
            {
                Response.Redirect("SomePage.aspx");
            }
        }
        protected void btnSave_Click(object sender, EventArgs e)
        {
            // Save Data Here
        }

                    This works great but this will effect the application scalability because it will abort a precious thread-pool thread. Now, just replace Response.Redirect("Unauthorized.aspx") with Response.Redirect("Unauthorized.aspx", false). This will solve the thread aborting issue but will not stop the current page life cycle. Means, you have to secure the btnSave_Click event(and all the other page events) because anyone can easily send a post request which allows the btnSave_Click event to execute. To solve this issue, I recommend to use this RedirectUser extension method,


    public static class HttpResponseExtensions
    {
        public static void RedirectUser(this HttpResponse response, string url)
        {
            if (response.IsRequestBeingRedirected)
                return;
            response.Redirect(url, false);
            var context = HttpContext.Current;
            if (context != null)
            {
                context.ApplicationInstance.CompleteRequest();
            }
        }
    }
    public partial class WebForm : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            var condition = .....;
            if (!condition)
            {
                Response.RedirectUser("Unauthorized.aspx");
            }
        }
        protected void btnSave_Click(object sender, EventArgs e)
        {
            if (Response.IsRequestBeingRedirected)
            {
                return;
            }
            // Save Data Here
        }
    }


                    The first benefit of using RedirectUser is that it will use the recommended Response.Redirect(with endResponse= false) method which is good for application scalability. The second benefit is that it will not overwrite the previous Response.Redirect(if any) if you are calling this method multiple times. The third benefit is that it will call HttpApplication.CompleteRequest which causes the ASP.NET run-time to by-pass all the events and filtering in the HTTP pipeline(not the page-life cycle pipeline). Also note that you still need to check Response.IsRequestBeingRedirected in the btnSave_Click event. I also prefer that you should put all your controls inside Response.IsRequestBeingRedirected check,

 

 

    <form id="form1" runat="server">
        <% if(!Response.IsRequestBeingRedirected){ %>
            <asp:Button ID="btnSave" runat="server" Text="Save" OnClick="btnSave_Click" />
            <%--All the Other Controls--%>
            <%--All the Other Controls--%>
            <%--All the Other Controls--%>
        <%} %>
    </form>


                    One another thing you need to take care when you use a complex control(like GridView, RadGrid, etc.) which have selecting, inserting, updating and deleting events. You must cancel the operation(insert, update or delete) if Response.IsRequestBeingRedirected is true in these events. Here is an example,

 

 

        
        protected void GridView1_RowEditing(object sender, GridViewEditEventArgs e)
        {
            if (Response.IsRequestBeingRedirected)
            {
                e.Cancel = true;
                return;
            }
        }

 

 


        Summary:


                    In this article, I showed you how to use Response.Redirect optimizely. I also showed some risks of using the optimized Response.Redirect and a technique to mitigate the risks. Hopefully you will enjoy my this article too.



9 Comments

  • Nice One Imran

  • good read, thanks for the information!

  • Don't mean to troll but this is another reason why I choose MVC over web forms any day now.

  • Thanks for the pointer Imran. Like Andrei, I prefer to use MVC nowadays, however my current client has a large number of legacy applications using web forms so this is a great help.

  • I don't know if its just some fake example but this has a very bad smell to me: It implies that security is being checked at the page level on every page.

    var condition = ......;
    if (!condition)
    Response.Redirect("Unauthorized.aspx");


    The suggested fix is terrible, maybe if you describe the fundamental problem that requires you to make such frequent checks in the page load, someone could suggest an appropriate way to approach it (maybe a pre_request handler or some such).

    Looking at this, I can understand why people think web forms is bad.

  • Very nice article - it still doesn't feel like you're getting to the root cause of the problem and are suggesting a bit of a hack workaround. Are webforms that poorly designed that the use of an out of the box function causes is such a performance hog?

  • @Anon, Yes it was a fake example. This article simply discusses the pitfall of Response.Redirect. I have updated the page name.

    If you see my first point in this article was "I was reviewing an ASP.NET Web Form application". Means I am talking about existing application that uses Response.Redirect badly. I never said that you should put your security checks there.

  • @Chris See this links,

    http://blogs.msdn.com/b/tmarq/archive/2009/06/25/correct-use-of-system-web-httpresponse-redirect.aspx

  • ldtKvC I think this is a real great article.Much thanks again. Keep writing.

Comments have been disabled for this content.