I have an ASP.NET MVC 3 application which has a post action called Create
:
[HttpPost]
public virtual ActionResult Create(Issues issues)
{
if (ModelState.IsValid)
{
context.Issues.Add(issues);
context.SaveChanges();
return RedirectToAction("Index");
}
return View(issues);
}
If I double click on the submit button by mistake, it'll Create 2x issues. Is there a way of preventing this, without the use of javascript and disabling the button, I thought the whole use of using a RedirectToAction
was to prevent this, by using the Post/Redirect/Get design pattern?
The pattern you mentioned (Post/Redirect/Get design pattern) prevents page refreshes from double posting because the last action is a GET, not the POST.
If you want to prevent double clicks from double posting, you could:
1. Disable the button after click
2. Maintain a unique index on 'Issues' and look for duplicates
3. Maintain something in session that gives you an indication of a double post
And there maybe a few more ways... I think disabling the button is probably the easiest because you're redirecting to another page anyway.
Easy solution!
Disable the submit button when it's clicked. The End.
$('submitButtonId').click(function(){
$(this).prop('disabled', true);
$(this).attr('disabled', 'disabled'); // for jQuery versions < 1.6.
});
Most simple way I can think of is use the Session:
if (ModelState.IsValid)
{
DateTime now = DateTime.Now;
if (Session["LastAdd"] == null || (now - (DateTime)Session["LastAdd"]).TotalMilliseconds > 1000)
{
//first time, or more than a second passed since last addition
context.Issues.Add(issues);
context.SaveChanges();
Session["LastAdd"] = now;
}
return RedirectToAction("Index");
}
You can generate an IssueId when you show the form to the user, then check that you don't already have an issue with such id in your Create method and, for example, skip such requests.
The PRG pattern will not prevent this, as the P action in it takes time (which is usually the case) and the user can submit the form again (via click or browser refresh), which will cause the PRG pattern to "fail".
Note that malicious users can also bypass all of your client side measures by running multiple http posts in quick succession.
A solution to all of the above is to check for duplicate submissions on server side using the following method, as described by myself, here.
For your convenience, I quote:
"If you make use of a hidden anti-forgery token in your form (as you
should), you can cache the anti-forgery token on first submit and
remove the token from cache if required, or expire the cached entry
after set amount of time.
You will then be able to check with each request against the cache
whether the specific form has been submitted and reject it if it has."