Simple jQuery Delete Link For ASP.NET MVC

UPDATE: I have a followup to this post that works for down-level browsers.

In a recent post, Stephen Walther pointed out the dangers of using a link to delete data. Go read it as it provides very good coverage of the issues. The problem is not restricted to delete operations. Any time you allow a GET request to modify data, you’re asking for trouble. Read this story about something that happened to BackPack way back in the day to see what I mean.

The reason that delete operations deserve special attention is that it’s the most common case where you would use a link to change information. If you were editing a product record, for example, you would use a form. But a delete operation typically only needs one piece of information (the id) which is easy to encode in the URL of a GET request.

If you are using jQuery, one simple way to turn any link into a POST link is to add the following onclick attribute value:

$.post(this.href); return false;

For example

<a href="/go/delete/1" onclick="$.post(this.href); return false;">Delete</a>

Will now make a POST request to /go/delete/1 rather than a GET. Of course, you need to enforce this on the server side. This is pretty easy with ASP.NET MVC.

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Delete(int id) {
  //Delete that stuff!
}

The AcceptVerbs attribute specifies that this action method only responds to POST requests, not GET requests.

At this point, you could easily write helpers specifically for delete links. I usually write very specific helper methods such as Html.DeleteProduct or Html.DeleteQuestion. Here’s an example of one I wrote for a sample app I’m building.

public static string DeleteAnswerLink(this HtmlHelper html, string linkText
  , Answer answer) {
    return html.RouteLink(linkText, "answer",
        new { answerId = answer.Id, action = "delete" }, 
        new { onclick="$.post(this.href); return false;" });
}

The nice thing about this approach is that you can leverage the existing helper methods by adding a minimal amount of extra information via the onclick attribute.

I hope the combination of Stephen’s post and this post will lead you to safer deleting.

Technorati Tags: ,,,

What others have said

Requesting Gravatar... Kevin Pang Jan 30, 2009 11:14 AM
# re: Simple jQuery Delete Link For ASP.NET MVC
I like the approach, although I wish there was a way to utilize it while still having graceful degradation for users with javascript disabled.
Requesting Gravatar... Ralph Whitbeck Jan 30, 2009 11:30 AM
# re: Simple jQuery Delete Link For ASP.NET MVC
@Kevin the nice thing though is that it won't work so there is no ability for errant deletes.
Requesting Gravatar... Kevin Pang Jan 30, 2009 11:44 AM
# re: Simple jQuery Delete Link For ASP.NET MVC
Yes, it's nice that you won't get errant deletes. It would be nicer if it would actually work so people with javascript disabled (or on mobile phones that don't support jQuery) can still use your site. :-)
Requesting Gravatar... ReneS Jan 30, 2009 11:49 AM
# re: Simple jQuery Delete Link For ASP.NET MVC
The common sense is: GET for fetching data, POST for modifying data.
Requesting Gravatar... Richard Spiller Jan 30, 2009 11:54 AM
# re: Simple jQuery Delete Link For ASP.NET MVC
@Kevin, if you look at the post by Stephen Walther that Phil mentions, he demonstrates a couple of other ways to provide safe delete links. One of which specifically addresses the issue of working well without Javascript. -HTH
Requesting Gravatar... Chad Myers Jan 30, 2009 11:55 AM
# re: Simple jQuery Delete Link For ASP.NET MVC
I'm not sure, but I do recall reading something once that putting JS in 'onclick' attributes is not preferable and can cause memory leaks or something. Forgive as I forget the specifics, but I do remember it being strongly advised against.

One thing you might consider is having a CSS class like "deleteLink" and then, in your document ready doing:


$(document).ready(function(){
$('.deleteLink').click(function(){
$.post(this.href); return false;
});
});

The jQuery experts seem to encourage this type progressive enhancement which has other benefits besides "not having JS in your markup."

The "What if Javascript is disabled?" problem is also an issue, but I'm guessing that if you have the requirement to support no-JS that you have other, larger issues than just delete links, lol.



Requesting Gravatar... Steve Jan 30, 2009 12:01 PM
# re: Simple jQuery Delete Link For ASP.NET MVC
Since you require jquery, it might make sense to take the onclick off and add a class instead, then unobtrusively use:
$("a.whatever").live('click', function(ev) { ev.preventDefault(); $.post(this.href); }
Requesting Gravatar... Steve Jan 30, 2009 12:03 PM
# re: Simple jQuery Delete Link For ASP.NET MVC
(Chad's comment above is correct, but won't work with AJAX content that's loaded later. That's the nice thing about jq 1.3's "live" events)
Requesting Gravatar... Chris Hardy Jan 30, 2009 1:30 PM
# re: Simple jQuery Delete Link For ASP.NET MVC
Phil,

On the subject of AcceptVerbs - is there ever going to be the option to put the AcceptVerbs attribute on a Controller so all actions on the controller will adhere to this unless overwritten on the action attribute? This will be useful when 80% of the methods on a API might be need to be post for reasons mentioned above (as they are Create/Edit and Delete actions).

ChrisNTR
Requesting Gravatar... haacked Jan 30, 2009 2:54 PM
# re: Simple jQuery Delete Link For ASP.NET MVC
@Steve ah, good point. I should try updating my sample. For down-level browsers, I could render a form with a submit button for deletion. Then the javascript could simply hide the form and do the submit itself.
Requesting Gravatar... Kazi Manzur Rashid Jan 30, 2009 3:12 PM
# re: Simple jQuery Delete Link For ASP.NET MVC
I think the whole issue is security not http get vs post or any client side scripting. No one should write any code against http Get that can modify data which makes the application vulnerable. Those who have played with early bits of ASP.NET Ajax(Atlas) or has pure (WebForm less) http progarmming already knows this issue.
Requesting Gravatar... Ricky Jan 30, 2009 3:39 PM
# re: Simple jQuery Delete Link For ASP.NET MVC
Agreed with Chad Myers on the better way to write this code...

BUT, this JavaScript doesn't provide any security at all. All I have to put on my evil page is a 1 pixel iframe with a form that auto posts on load to that URL.

Isn't this the point of the Anti-Request Forgery token thingy you guys have in the framework or futures?
Requesting Gravatar... Ricky Jan 30, 2009 3:45 PM
# re: Simple jQuery Delete Link For ASP.NET MVC
And BTW, $.post(url) will do an XHR (AJAX) POST so you will not see anything happen if you don't add a callback to handle the response...
Requesting Gravatar... haacked Jan 30, 2009 4:05 PM
# re: Simple jQuery Delete Link For ASP.NET MVC
@Ricky yeah, I haven't addressed the CSRF aspect of this, which is probably something I should cover.
I did create a new post addressing the downlevel browser issue.
Requesting Gravatar... configurator Feb 01, 2009 6:20 AM
# re: Simple jQuery Delete Link For ASP.NET MVC
Phil, you could easily render a form with nothing but a submit button:

<form method="post"><input type="submit" value="Confirm delete" /></form>

This would render in the delete action when accessed with GET - i.e. browsers without javascript. So there would be no need to use javascript to submit the form; nobody with javascript would see it.
Requesting Gravatar... Mark Feb 01, 2009 3:41 PM
# re: Simple jQuery Delete Link For ASP.NET MVC

Just use css to make your submit button look like a link, Done, simple.

Forget all the javascript etc.
Requesting Gravatar... Slashene Feb 15, 2009 1:52 AM
# re: Simple jQuery Delete Link For ASP.NET MVC
Why not using the DELETE verb instead of POST ???
Requesting Gravatar... haacked Feb 15, 2009 9:09 AM
# re: Simple jQuery Delete Link For ASP.NET MVC
Impossible to make a DELETE request from a downlevel browser.
Requesting Gravatar... Ruairi Apr 07, 2009 7:40 AM
# re: Simple jQuery Delete Link For ASP.NET MVC
I'm "trying" to do best practice by POSTing when doing a delete, but I'm guessing I should be using the [ValidateAntiForgeryToken] attribute with the post. Am I going to far with this security with CSRF?

The page gets messy because the API creates the token in a hidden form field, but If I'm doing a JQuery $.post(...) I'd prefer the token without the hidden element. Curently I've got Jquery traversing the HTML to find the

$('input[hidden]').attr('value')

Any suggestions?
Requesting Gravatar... Kara Jan 14, 2010 1:06 AM
# re: Simple jQuery Delete Link For ASP.NET MVC
I have a simple [href] tag which use to open aspx page inside jquery modal popup. but when click the image, redirect to "can not find page". basically can' t recognize the URL. here is what i' m talking about:-

<img src="../../App_Themes/DefaultTheme/images/car.jpeg" alt="" border="0px" />

Please, any idea about this?
Requesting Gravatar... ASM Feb 20, 2010 9:56 AM
# re: Simple jQuery Delete Link For ASP.NET MVC
It's still very dangerous no matter what you as long as there is an action to delete records from the DB. I can simply type in the address bar of the browser after the document is loaded
Javascript:$.post('/Home/Delete/1'); and it will delete.

Mind you every thing you put in the page is exposed wheather it's a hidden field or whatever. Javascripst is not good if you allow it to handle operations that should be made on the server side.

You should not use Ajax or Javascript to delete anything from the DB. it's very risky and it is EXPOSED
Requesting Gravatar... ASM Feb 20, 2010 10:47 AM
# re: Simple jQuery Delete Link For ASP.NET MVC
What if there is a mechanism to encrypt/decorate action names?

I also think the javascript call should be tied with a control of the page's chidren tree not any source.
Requesting Gravatar... Andrew Siemer Apr 20, 2010 9:06 PM
# re: Simple jQuery Delete Link For ASP.NET MVC
Phil,

Great little snippet! It inspired a recipe in my "ASP.NET MVC Cookbook" (currently towards the end of chapter 5) to be posted here shortly: groups.google.com/.../aspnet-mvc-2-cookbook-review

Thanks for sharing.

Andrew Siemer
Requesting Gravatar... m-r Tarakanoff Jun 03, 2010 2:58 AM
# re: Simple jQuery Delete Link For ASP.NET MVC
I immediately rewrote their draft in the light of this message :) Thank!
Requesting Gravatar... Stephen Wilson Aug 07, 2010 3:49 PM
# re: Simple jQuery Delete Link For ASP.NET MVC
Hi Phil,

Thanks for this tip! I am having a small issue using it however that I hope you could shed some light on.

Currently I have the link:

<code<% Response.Write(supplier.IsActive ? "Deactivate" : "Activate"); %>

This works fine and fires the 'Activate' action:


[HttpPost]
[Authorize]
public ActionResult Activate(int id)
{
SupplierRepository sr = new SupplierRepository();
Supplier supplier = sr.GetSupplier(id);
sr.SetSupplierActive(id, !supplier.IsActive);

return RedirectToAction("Index");
}


Which in turn fires the index action:


[Authorize]
public ActionResult Index()
{
SupplierRepository sr = new SupplierRepository();

return View(new SuppliersViewModel
{
suppliers = sr.GetAllSuppliers().ToList()
});
}


But because I am redirecting back to the same page that made the post (at least thats what I think the issues is) The page does not get updated / re-rendered.

Letting the link fire as a 'get' request works fine, presumably because in the browsers mind it has gone somewhere, so the re-render is necessary.

I have tried to find a solution for this but all the search terms I could think of to find an answer didnt come up with anything.

This seams like a pretty basic issue, what am I missing?

Thanks

Stephen.
Requesting Gravatar... Frank Aug 23, 2010 3:46 AM
# re: Simple jQuery Delete Link For ASP.NET MVC
Who still uses down-level browsers? Even the worst UK govt depts are are on IE 3.0. Surely lynx has died by now

What do you have to say?

(will show your gravatar)
Please add 3 and 4 and type the answer here: