RedirectToAction not refreshing the page as expected - c#

What am I doing wrong with my MVC code here ? The Index view includes a form that submits to itself, what I'd like is the controller to process the submitted form and then return to the View.
What actually happens is the form is processed correctly, but the View returned is as if nothing happen (e.g. ids that have been deleted are still shown). If I manually refresh the page though, it displays correctly again. I don't think it's broswer caching related, as redirecting to the same view from a different controller works fine. How can I fix it ?
public ViewResult Index()
{
return View(GetComments());
}
[HttpPost]
public ActionResult Index(int[] AllIds)
{
if (AllIds != null)
{
foreach (int id in AllIds)
{
// do stuff
}
}
return RedirectToAction("Index");
}
Edit: When submitting the form, the breakpoint on the first method is not hit and trying to "Step Into (F11)" the return RedirectToAction("Index"); line just moves straight onto the final } instead.

Install Fiddler or Firebug for Firefox and watch the traffic, see it it really returns a new response or a HTTP 304 from the browser(cached page). If everything checks out then you have a problem with your db persistence and or queries.

Have you tried this? I'm wondering, depending on how you persist the data, if it's not being saved until after the server returns a response..?
public ViewResult Index()
{ // breakpoint
var comments = GetComments(); // debug and inspect the value of this variable
return View(comments);
}
[HttpPost]
public ActionResult Index(int[] AllIds)
{
if (AllIds != null)
{
foreach (int id in AllIds)
{
// do stuff
}
}
return RedirectToAction("Index"); // breakpoint
}
I know some people use an IUnitOfWork in MVC that only calls SaveChanges / Commit on the ORM at the end of the request. Is it possible that the // do stuff removes items from the collection, but does not persist to the db until AFTER the GET Index() is returned?
Update
Instead of return RedirectToAction("Index"), have you tried RedirectToAction(Index())?

Try entering controller name as well. That helped me. For example:
return RedirectToAction("Index","Home");

Related

HttpPost method receiving wrong data?

I have two methods:
public ActionResult EditNote(int? id)
{
NotesModel edit = NotesProcessor.LoadNote(Convert.ToInt32(id));
if (edit.Author != Session["UserName"].ToString())
{
edit.Id = null;
edit.Title = null;
edit.Note = null;
edit.Author = null;
return View(edit);
}
return View(edit);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult EditNote(NotesModel model)
{
if(model.Id == null) NotesProcessor.SaveNoteEdit(model);
else
{
model.Author = Session["UserName"].ToString();
NotesProcessor.SaveNote(model);
}
return View();
}
I've simplified the code to only show the problematic part which is:
A logged in user is trying to edit a note which they're not allowed to because it was made by another user. So all the values are set to null so the user will create a new note. The first method will receive an id to search the database for the note the user is trying to edit.
In the next HttpPost method however model.Id is still the same as the integer received by the first method despite changing all the values to null in the first method.
The first method is called from the views page like this:
#Html.ActionLink("Edit", "EditNote", new { id = Model.Id })
Anyone got an idea whats going on here?
You are actually not posting anything to the system as it seems, you are just calling the HttpGet method via URL and then clearing out the view model data at page level only. So, it seems your HttPost method is not even hitting. Try debugging and see whether your HttpPost method gets hit.
You don,t even need to create two methods for what you want to achieve. All you need is just single HttpPost method.
For HtpPost method to be called, you need to either create Form control at UI level with action type as post or you need to hit HttpPost method via JavaScript / JQuery
I hope this helps.

How do I return a different ActionResult from my controller that takes arguments?

I have a Controller with some actions on it as follows:
[HttpPost]
public ActionResult Create(CreateModel model)
{
if (model.SelectedCustomers.Count > 0 &&
model.SelectedVersions.Count > 0 &&
!string.IsNullOrWhiteSpace(model.ScriptName) &&
!string.IsNullOrWhiteSpace(model.ScriptText))
{
Script script;
...save to database...
return Edit(script.Id); //<---------Return other view here
}
else
{
...
}
}
[HttpGet]
public ActionResult Edit(int? scriptId)
{
return View();
}
After the Create action runs, and saves my model to the database successfully, I want to send the user to the Edit view for the newly created script. When I use the code above, specifically return Edit(script.Id); it just sends the user back to the Create view instead of the Edit view. When the user navigates to the Edit action directly, or through the result of an Html.ActionLink pointed at Edit everything works correctly.
What am I doing wrong?
This isn't doing what you think it does:
return Edit(script.Id)
It's not actually telling the framework to go to that action. It's just returning the return value of that method. Purely a C# concern before any components of the ASP.NET MVC Framework are involved at all. And what is that return value:
return View()
So the former is really functionally the same thing as the latter. And any time you use return View() in ASP.NET MVC, the framework will determine that view by examining the action currently being called, which in this case is Create.
What you want isn't to return the Edit view (even if you do, in this case, the user is still on the Create URL, which will cause confusion). What you want is to return a redirect to tell the client to request that next action:
return RedirectToAction("Edit", new { scriptId = script.Id });
You can always call RedirectToAction and return that action result. That will inform the browser to redirect to the different action.
I think you will need something like this:
return RedirectToAction("Edit", new { scriptId = script.Id });
Calling Edit directly is no different than calling a method.
You can do with this RedirecToAction with input parameters.
return RedirectToAction("Action", new { id = 12 });
In Your Case:
return RedirectToAction("Edit", new { scriptId = script.Id });

How to keep hidden field data not in model after validation error [MVC]

I have this neat model, which is populated on a screen and inserted to a database on successful validation. To make the web app easier to use, I make it redirect to a specific URL after it posts the data. To do that, I pass the URL as a hidden field (the URL is dynamic and depends on the Get request). Of course, on failed validation the model is returned and textboxes and other editors are repopulated, but the hidden field with the URL is not. How can I make it repopulate after validation error, without it beign the part of the model?
Here's some of my code:
-get method:
public ActionResult Create()
{
ViewBag.returnUrl = System.Web.HttpContext.Current.Request.UrlReferrer; ....
-post method:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "Issue_ID,Issue,Case_Status,
Issued_by,Issue_Date...,HelpDesk_Service_Request_Ticket_Number")] Case #case, string returnUrl)
.
.
.
if (ModelState.IsValid)
{
db.Cases.Add(#case);
db.SaveChanges();
if (returnUrl == null)
{
return RedirectToAction("Index");
}
else
{
return Redirect(returnUrl);
}
}
return View(#case);
Thanks in advance!
From you question I understand you want to pass the return url value from one action (GET) to another (POST). You can store the value in TempData
TempData["returnUrl"] = new Uri("<return url>");
and then try accessing it using
var returnUrl= TempData["returnUrl"];
Note that once the value is read from TempData, it is automatically removed from the collection. For retaining the value you can use keep() or peek() method. Please refer a similar question answered here
Viewbag only lives for current request. You need to use TempData instead.
Please check this thread Viewbag passing value

MVC #Html.ActionLink no-op from controller

I have an #Html.ActionLink inside of a partial view that when clicked I'd like to have either send the user to another view or stay on the current view without changing anything. Is this possible?
Our controller looks like:
public ActionResult Edit(int id)
{
if (ShouldAllowEdit(id))
{
return this.View("Edit", ...edit stuff...)
}
return ????????
}
We tried return new EmptyResult(); but that just dumps the user to a blank page.
This is a little different approach to the issue, but it should do what you want.
Instead of giving the user a link to navigate to, do an ajax call on link/button click, and do the id check. Return either the url to navigate to in a JsonResult, or nothing if the id is invalid.
On return of the ajax call, navigate to the url if appropriate.
(swap out the hard coded ids and the == 0 with your ShouldAllowEdit function in the example of course)
In the View:
<div class="btn btn-danger" id="myButton">Button</div>
#section scripts{
<script>
$("#myButton").click(function () {
$.ajax("#Url.Action("Edit", new { id = 0 })", { type : "POST" })
.success(function (data) {
if (data.url !== "") {
window.location.href = data.url;
}
});
});
</script>
}
In the controller:
[HttpPost]
public JsonResult Edit(int id)
{
if (id == 0)
{
return Json(new {url = ""});
}
else
{
return Json(new { url = Url.Action("EditPage", new { id = id }) });
}
}
An answer is to redirect to the view action - and maybe give some feed back why they failed.
public ActionResult Edit(int id)
{
if (ShouldAllowEdit(id))
{
return this.View("Edit", ...edit stuff...)
}
ModelState.AddModelError("id", "Not allowed to edit this item");
return RedirectToAction(Edit(id));
}
If the user clicks a link they will be taken away. They might be sent back right to the same page, but the page will unload, be requested from the server again, and then re-rendered in the browser. If you don't want that to happen, you don't give the user the link in the first place. In other words, conditionally render the link or not based on the user's roles or whatever.
#if (userCanEdit)
{
#Html.ActionLink(...)
}
Where userCanEdit is whatever logic you need to make that determination.
If the user fails whatever check you determine, then they don't get the link. Simple.
However, since there's malicious people in the world, you can't just leave it entirely there. There's potential for the user to figure out the link to edit something and go there manually. So, to prevent that you check for the edit permission in your action (like you've already got in your code sample), but if the user is not allowed, then you just return a forbidden status code:
return new HttpStatusCodeResult(HttpStatusCode.Forbidden);
Or
return new HttpStatusCodeResult(403);
They both do the same thing.
UPDATE
Based on your comment above, it appears that the user is normally allowed to edit but can't in a particular instance because another user is editing. A 403 Forbidden is not appropriate in that case, so really all you've got is a simple redirect back to the page they were on, perhaps with a message explaining why they're back there.
TempData["EditErrorMessage"] = "Sorry another user is editing that right now.";
return RedirectToAction("Index");

pass value from post back to get with RedirectToAction

Using MVC - 'Index' functions loads page, values are past back to 'IndexPost', updates are made and at the end of the post the index is reloaded.
return RedirectToAction("Index");
If the event updates are made in the post I would like to make changes in the original 'index' function to do this need to pass a value from the post to the get....
something like
return RedirectToAction("Index", userId);
then in the original get:
public ActionResult Index(int? userId)
How can this be done?
thank ye
If I understand your question you have to use
return RedirectToAction("Index", new { userId = userId } );

Categories

Resources