I'm following Stephen Walther's tutorial on safely deleting via POST + AJAX (found here: http://stephenwalther.com/blog/archive/2009/01/21/asp.net-mvc-tip-46-ndash-donrsquot-use-delete-links-because.aspx), but am having problems he did not mention in his article.
I modified his code slightly, so that I have an Index.aspx file which contains a Movies.ascx partial view. The partial view is strongly typed, and is where my delete link lives. The delete logic is as such:
public ActionResult Delete(int id)
{
var movieToDelete = (from m in _entities.MovieSet
where m.Id == id
select m).FirstOrDefault();
_entities.DeleteObject(movieToDelete);
_entities.SaveChanges();
return RedirectToAction("Index");
}
When a delete link is clicked, Delete is called, the object is deleted, and RedirectToAction returned. However, the page doesn't update. If you click the link again, an exception is thrown (since the object with that ID is already deleted), and the page updates. Remembering I was working with partials, I changed the return to
return PartialView();
thinking it would fix the problem, but it had no effect. The object is still deleted and the page never refreshed.
I'm stumped - not sure where the problem is at this point, seems to be a something wrong with my return, but I'm not sure.
since you're deleting using ajax, why don't you try delete the object from the dom or return the new data on success. Check out these examples: here or here.
Related
I'm just starting out with ASP.NET MVC, and anything but the basics throws me at the moment, so please bear with me.
I am writing a little application á la UserVoice, whereby users can post ideas, and other users can vote for those posts.
I have a View which displays the detail of a particular Post (suggestion). On that View I have button labelled Vote which, when clicked, should create a record in my database's PostVote table linked to the Post. I just can't get this work, though! Here's what I have:
Post > Details.cshtml
Vote
PostVoteController.cs
[HttpPost]
public ActionResult VoteForPost(int id, Post post)
{
if (ModelState.IsValid)
{
db.PostVote.Add(new PostVote
{
PostID = id,
VoteTime = DateTime.Now,
VoteUser = UserHelper.GetUsername()
});
db.SaveChanges();
}
return View(post);
}
The only reason I'm requiring the post parameter in my method is because, as I understand it, unless I want to use Ajax I need to use an ActionResult and return a View, and so I've tried to copy the code in the Edit method of the PostController which was generated automatically by Visual Studio and works fine. The idea is just to reload the Post Details View after the new PostVote record has been created,
I realise I've probably written nonsense, but nothing I'm trying works. When I click the Vote button, I'm directed to a page with a URL of http://localhost:58974/PostVote/VoteForPost/1, which I sort of understand, but is obviously wrong. I can't figure out how to just pass the ID of the Post to which the new PostVote record should be linked as a variable rather than it forming part of the URL. Obviously I get a 404 error because the page doesn't exist.
Update
Ok, thanks to the comments posted I've now got this in my View:
#using (Html.BeginForm("VoteForPost", "PostVote", new { id = Model.PostID }, FormMethod.Post))
{
<button type="submit">Vote</button>
}
This is successfully creating the records as desired, but is still trying to redirect the browser to http://localhost:58974/PostVote/VoteForPost/1 afterwards. Bearing mind that the Controller (PostView.cs) doing the record creation is not the one which displayed the Post Details in the first place (that's Post.cs), how do I get my method to just return me back to the Details View I'm already looking at?
It's rather complicated to explain but I'll try if there's anything unclear feel free to ask.
I have a page on which I'm editting a dbcontext object through the View of his model(automatically created after making a Model and adding a Dbcontext). However there's also a possibility to contact an external source(LinkedIn) to retrieve this particular information. Because of this I put this link on my page in which the object is being edited: #Html.ActionLink("Login with LinkedIn", "AuthenticateToLinkedIn", "LinkedIn")
however when I return to the edit page with this code:
int userid1 = Convert.ToInt32(Membership.GetUser().ProviderUserKey.ToString());
List<Person> test = (from p in db.Persons where p.userid == userid1 select p).ToList();
//go back to the original page.
return RedirectToAction("Edit", "Person", test[0].ID);
It throws an exception that the object is already being modified. This is logical as it most likely saves the earlier page in the memory(I assume my webpage does this not me in my code) thus he thinks the same object is loaded twice which means the object will be conflicted. How could I possibly prevent this though? I was thinking perhaps returning to the original page or a redirect through another page. What are your thoughts on this? And how should I do that because I honestly have no clue how to access the cache or something like that.
I have a usercontrol that is rendering a list of items. Each row contains a unique id in a hidden field, a text and a delete button. When clicking on the delete button I use jquery ajax to call the controller method DeleteCA (seen below). DeleteCA returns a new list of items that replaces the old list.
[HttpPost]
public PartialViewResult DeleteCA(CAsViewModel CAs, Guid CAIdToDelete)
{
int indexToRemove = CAs.CAList.IndexOf(CAs.CAList.Single(m => m.Id == CAIdToDelete));
CAs.CAList.RemoveAt(indexToRemove);
return PartialView("EditorTemplates/CAs", CAs);
}
I have checked that DeleteCA is really removing the correct item. The modified list of CAs passed to PartialView no longer contains the deleted item.
Something weird happens when the partial view is rendered. The number of items in the list is reduced but it is always the last element that is removed from the list. The rendered items does not correspond to the items in the list/model sent to PartialView.
In the usercontrol file (ascx) I'm using both Model.CAList and lambda expression m => m.CAList.
How is it possible for the usercontrol to render stuff that is not in the model sent to PartialView?
Thanx
Andreas
It sounds like the ModelState is the trouble here, as you bind to CAs the ModelState save this values in the background as Attempted Values, so its true the object is no longer present at the Model, but the ModelSate still have the values of the deleted object. You can try a:
ModelState.Clear();
To remove all those old values.
Check in firebug what the response realy is. This way you can see if you have a serverside problem or it is a jquery issue.
I am stuck with redirecting problem in ASP.NET MVC project. I have mapped tables via LINQtoSQL and each has unique ID as primary key.
I am implementing functionallity of 'CREATE'. Basically, after new value is added into SQL table (which means I pressed Save button), I want to be redirected to Details of this freshly added item.
Here's little code how I am doing it :
[AcceptVerbs(HttpVerbs.Post), Authorize]
public ActionResult Create(Item item) {
....
return RedirectToAction("Details", new { id = item.ItemID });
Trouble is, I am never redirected to Details view (I have Details.aspx view for items).
When I check CallHierarchy in Visual Studio (2010 pro) the hierarchy is indeed little strange, like this :
RedirectToAction(string,object)
Calls To 'RedirectToAction'
Create
Calls To Create (no results)
Calls From Create (methods of created instance. From there I'll get back to 'RedirectToAction' and to 'Calls to Create' and 'Calls From Create' etc. etc. - loop
Edit
Calls From 'RedirectToAction'
Not supported
I am looking for some tools or more specifically 'know how' (since VS probably has some tools) to debug this kind of situations.
PS: rooting is default :"{controller}/{action}/{id}",
Thanks
Checck your routes with Phil Haack's Route Debugger. Make sure that the correct route is being used, and the correct controller method is being called.
Use the debugger to step to the line where RedirectToAction is called. Confirm that the line is realy hit. Press F5 to continue after it.
Once the code is executed check in Firebug under network if a 302 is emitted.
See what is in the details for the request.
If no 302 is emitted I would try return RedirectToAction("Index") just to know if the call to details is wrong or there is another error.
You would need in the same controller
public ActionResult Details(int id)
{
return View();
}
in additon to the Details.aspx view.
I have a Product controller with Index action, which basically creates the view form for post and Index (Post action verb) action on the ProductController which basically save the product to db but when validation errors occur, I am returning a View(mymodel) else when saved, I am returning RedirectToAction("Created,"Product") but for some odd reason when I break into the code , it is hitting the Product Controller action twice rather than just once. Hence the product has 2 records instead of one.
public ActionResult Index()
{
return View()
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Index(FormCollection fc)
{
// 2 calls are made to this controller
try
{
// save the product
return RedirectToAction("Created");
}
catch(Exception ex)
{
// recreate the model from form collection
return View(viewData); // when a validation error occurs it comes into the catch block
}
}
Sometimes I have found Firebug to cause this behavior. Try disabling its Script panel, if you have it installed.
Explanation: In some cases Firebug isn't able to get the script sources for the display within its Script panel. In these cases it initiates a second request to get them. See issue 7401 for some discussion about this, which alleviates the problem and is fixed with Firebug 2.0.2.
Here's a basic checklist (copied from here):
Check that you don’t have any image or another elements in the View with an
empty src attribute (<img src=”" /> for example) or have src
attribute referencing something that no longer exists. You better
check directly in the browser's “Page Source”, than in the View itself due to the
possibility of some “dynamic” issues when the View is rendered. Once you
find such empty element in the page's HTML source its usually trivial to
find the same element in your View and fix the issue. This can also happen with <link href="">.
Check that you don’t have any AJAX calls referencing an empty URL (browsers will interpret such empty URL as the current page and will request the current page again making the Controller action execute few times).
You forgot to return “false” from the JavaScript click event handler for a link or button that makes an AJAX call. If you forget to “return false”, the browser simply interprets the default action of the link – regular, non AJAX, calling the same page again)
Sometimes Firebug and YSlow [ Firefox (FF) plugins ] can cause such issues. Just temporarily disable them in FF or test with a different browser.
Watch out for duplicate filters decorating your controller or action. (this was my problem)
Another solution for this case..
I had exactly same problem, running and testing from Chrome. I couldn't debug it because the second call was coming from (external call). I have randomly tested it in Firefox and Internet Explorer where there was no double hit.
Whatever nasty thing it was, I have deleted Chrome cache (everything!!!) and problem has been resolved.
Hope it will help some of you :)
I had a similar issue with a controller action that generated an image, and I was only seeing it with Firefox. There is a really old bug that causes this, that I guess is still there.
https://bugzilla.mozilla.org/show_bug.cgi?id=304574