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.