Stuart’s Blog

Safe Delete Links in ASP.NET MVC

Posted in Uncategorized by stuart on November 20, 2008

The problem, as explained by Jason Fried at 37Signals:

Google’s web accelerator seems like a good thing for the public web, but it can wreak havok on web-apps and other things with admin-links built into the UI. How’s that?

The accelerator scours a page and prefetches the content behind each link. This gives the illusion of pages loading faster (since they’ve already been pre-loaded behind the scenes). Here’s the problem: Google is essentially clicking every link on the page — including links like “delete this” or “cancel that.” And to make matters worse, Google ignores the Javascript confirmations. So, if you have a “Are you sure you want to delete this?” Javascript confirmation behind that “delete” link, Google ignores it and performs the action anyway

The root of the problem is that links generate GET requests, which should be ’safe’, so they’re not strictly appropriate for modifying actions like deletes.  However, it’s not always aesthetically viable to use a button inside a form

I’ve taken the approach taken used in Rails, which is to use javascript to inject a form when the link is clicked that will submit a POST request to the correct url.  Web accelerators and search engines will pass over the link harmlessly, but it will work within the browser as long as javascript is enabled

Two step implementation.  First, add a DeleteLink extension method

public static string DeleteLink<TController>(this HtmlHelper helper, Expression<Action<TController>> action, string text, string confirmation_text) where TController : Controller
{
var action_address = helper.BuildUrlFromExpression<TController>(action);

const string link_format = “<a href=’#’ onclick=\”if (confirm(‘{1}’)) {{ var f = document.createElement(‘form’); f.style.display = ‘none’; this.parentNode.appendChild(f); f.method = ‘POST’; f.action = ‘{0}’;f.submit(); }};return false;\”>{2}</a>”;

return string.Format(link_format, action_address, confirmation_text, text);
}

Note: string.Format needs double curly braces to emit a single curly

That can be called in the view like

<%= Html.DeleteLink<ListingsController>(l => l.Delete(listing.id), "Delete listing", "Delete this listing?") %>

Postlink would be a more apt name since it’s not specific to deletes, but I’ve left mine as DeleteLink since that’s how I’m using it

Finally, decorate modifying actions such that they only accept the correct verbs to be safe

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Delete(int id)
{
...
}
Tagged with:

Leave a Reply