Search code examples
c#jqueryasp.netasp.net-mvcasp.net-mvc-4

Prevent Double Submit / Post on ASP.NET MVC page


I am hoping for some feedback about the method I intend to use for preventing duplicate records in an ASP.NET MVC 4 application, and the knock on effects I have not though of for the users experience.

The web form has six input fields and a save button (as well as a cancel button), Users can take up to 10 minutes filling in the form.

Once the fields are submitted via a post the page is redirected on success / failure to a different page, after the data is recorded in a database table using a new Guid as the primary key.

To stop the users pressing the save button many times, but allowing the browser to repost the request on a closed connection I intend to provide the Guid for the new records primary key as a hidden input field when the form is rendered.

If the repost happens, or the user presses save multiple times, the database server will reject the second post of the record because of a duplicate key, which I can check for and cope with server side.

But does this create bigger problems for me?


Solution

  • If you make use of a hidden anti-forgery token in your form (as you should), you can cache (on server side) 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.

    You don't need to generate your own GUID as this is already being done when generating the anti-forgery token.

    UPDATE

    When designing your solution, please keep in mind that each request will be processed asynchronously in its own separate thread on the server, or perhaps even on entirely different servers / app instances.

    As such, it is entirely possible that multiple requests (threads) can be processed even before the first cache entry is made. To get around this, implement the cache as a queue. On each submit(post request), write the machine name / id and thread id to the cache, along with the anti-forgery token... delay for a couple of milliseconds, and then check whether the oldest entry in cache/queue for that anti-forgery token corresponds.

    In addition, all running instances must be able to access the cache (shared cache).