How can I ignore an http request without clearing the browser?
To prevent duplicate requests (i.e. pressing F5 right after clicking a command button), I've setup my page base class to ignore the request if it's detected as a duplicate.
When I say 'ignore' I mean Response.End()
Now I thought I've seen this work before, where there's an issue, I just Response.End() and the users page just does nothing. I don't know the exact circumstance in whi开发者_如何学Goch this worked, but I'm unable to repeat it now.
Now when I call Response.End(), I just get an empty browser. More specifically, I get this html.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML><HEAD>
<META http-equiv=Content-Type content="text/html; charset=utf-8"></HEAD>
<BODY></BODY></HTML>
I setup the following test app to confirm the problem is not elsewhere in my app. Here it is:
Add the following to an aspx form
<asp:Label ID="lbl" Text="0" runat="server" /><br />
<asp:Button ID="btnAdd1" Text="Add 1" runat="server" /><br />
<asp:Button ID="btnAdd2" Text="Add 2" runat="server" /><br />
<asp:Button ID="btnAdd3" Text="Add 3" runat="server" /><br />
And here's the code behind file
using System;
namespace TestDupRequestCancellation
{
public partial class _Default : System.Web.UI.Page
{
protected void Page_Init(object sender, EventArgs e)
{
btnAdd1.Click += btnAdd1_Click;
btnAdd2.Click += btnAdd2_Click;
btnAdd3.Click += btnAdd3_Click;
}
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
CurrentValue = 0;
else if (Int32.Parse(lbl.Text) != CurrentValue)
Response.End();
}
protected void Page_PreRender(object sender, EventArgs e)
{
lbl.Text = CurrentValue.ToString();
}
protected int CurrentValue
{
get
{
return Int32.Parse(Session["CurrentValue"].ToString());
}
set
{
Session["CurrentValue"] = value.ToString();
}
}
void btnAdd3_Click(object sender, EventArgs e)
{
CurrentValue += 3;
}
void btnAdd2_Click(object sender, EventArgs e)
{
CurrentValue += 2;
}
void btnAdd1_Click(object sender, EventArgs e)
{
CurrentValue += 1;
}
}
}
When you load the page, clicking any button does what is expected, but if you press F5 at any time after pressing one of the buttons, it will detect it as a duplicate request and call Response.End() which promptly ends the task. Which leaves the user with an empty browser.
Is there anyway to leave the user with the page as it was, so they can just click a button?
Also; please note that this code is the simplest code I could come up with to demonstrate my problem. It's not meant to demonstrate how to check for dup requests.
EDIT: Another change that will allow me to achieve the same results would be to disable all my event handlers. Is that possible?
If you're checking validators before executing your events, then hooking into your validation functionality might be the most unintrusive way to accomplish this.
try this:
using System;
using System.Web.UI.WebControls;
namespace TestDupRequestCancellation
{
public partial class _Default : System.Web.UI.Page
{
protected void Page_Init(object sender, EventArgs e)
{
btnAdd1.Click += btnAdd1_Click;
btnAdd2.Click += btnAdd2_Click;
btnAdd3.Click += btnAdd3_Click;
AddFirstPostbackValidator();
}
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
CurrentValue = 0;
}
protected void Page_PreRender(object sender, EventArgs e)
{
lbl.Text = CurrentValue.ToString();
}
protected int CurrentValue
{
get
{
return Int32.Parse(Session["CurrentValue"].ToString());
}
set
{
Session["CurrentValue"] = value.ToString();
}
}
private void AddFirstPostbackValidator()
{
CustomValidator val = new CustomValidator();
val.ID = "DuplicatePostbackValidator";
val.ErrorMessage = "Browser refresh detected. Command ignored.";
val.ServerValidate += val_ServerValidate;
Validators.Add(val);
form1.Controls.AddAt(form1.Controls.IndexOf(lbl) + 1, val); // user feedback
}
void val_ServerValidate(object source, ServerValidateEventArgs args)
{
args.IsValid = Int32.Parse(lbl.Text) == CurrentValue;
}
void btnAdd3_Click(object sender, EventArgs e)
{
if (!IsValid)
return;
CurrentValue += 3;
}
void btnAdd2_Click(object sender, EventArgs e)
{
if (!IsValid)
return;
CurrentValue += 2;
}
void btnAdd1_Click(object sender, EventArgs e)
{
if (!IsValid)
return;
CurrentValue += 1;
}
}
}
Don't force the response to end. Let it end gracefully (fall through), without going through your "main" logic for legitimate requests. If this proves to be too much work, then your code probably needs to be refactored. Or, the lazy way out, you can setup a global boolean indicating the validity of the requests (set in your Page_Load), and then check it throughout the rest of your code as needed.
EDIT
The more I think about this, I am more leaning to a more user-friendly approach. Instead of ending the request, how about redirecting them to a page dedicated to informing them of how to avoid duplicate requests in the site? This is what my bank web site does.
See if sending HTTP response code 204 No Content does what you want.
精彩评论