How to debug RedirectToAction - asp.net-mvc

I am trying to debug a problem wherein RedirectToAction appears to be working properly (i.e., the redirected-to Action is executed) but the specified View is never rendered on the client side and the url is not rewritten. My question is really where can I be looking to debug this? Here's the code:
Form:
<%using (Html.BeginForm("Save", "Items", FormMethod.Post, new {id="ItemForm"})) {%>
<%=Html.AntiForgeryToken()%>
..form contents elided...
<%= Html.Button("btnSave", ViewData.Model.SaveMethod, HtmlButtonType.Submit) %>
<%= Html.Button("btnCancel", "Cancel", HtmlButtonType.Button,
"window.location.href = '" + Html.BuildUrlFromExpressionForAreas<ItemsController>(c => c.Index()) + "';") %>
<% } %>
Controller:
[ValidateAntiForgeryToken]
[Transaction]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Save(Item item)
{
if (item.Id == Guid.Empty)
return Create(item);
return Edit(item);
}
[ValidateAntiForgeryToken]
[Transaction]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(Item item)
{
if (ViewData.ModelState.IsValid)
{
ActionConfirmation updateConfirmation =
_itemManagementService.UpdateWith(item, item.Id);
if (updateConfirmation.WasSuccessful)
{
TempData[ControllerEnums.GlobalViewDataProperty.PageMessage.ToString()] =
updateConfirmation.Message;
return RedirectToAction("Index");
}
}
ItemFormViewModel viewModel =
_itemManagementService.CreateFormViewModelFor(item, _indicatorManagementService, _strategyManagementService);
return View(viewModel);
}
[Transaction]
public ActionResult Index()
{
ItemsFormViewModel viewModel = _itemManagementService.CreateListFormViewModel(_indicatorManagementService,
_strategyManagementService);
return View(viewModel);
}
I am using a custom model binder, but model.IsValid returns true and the changes to the model save successfully. I am at a loss as to where to look to track this down.
Thanks for looking.

As always, as soon as I post, I finally figure it out. Had some left over jquery from a previous approach that was hijacking the submit.

Related

Hijacked Umbraco HttpPost action not firing

I've hijacked the route in Umbraco 7.1 and for some reason my HttpPost is not firing when the submit button is pressed. Any input as to why this is? There is a postback taking place when send is pressed but the when putting a break point in the HttpPost it's never fired.
Here's a snippet of my code, the markup followed by the controller.
#inherits UmbracoViewPage
#{
Layout = "Layout.cshtml";
}
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.TextAreaFor(m => m.Message)
< i n p u t type="submit" value="Send" />
#Html.ValidationMessageFor(m => m.Message)
</div>
}
public ActionResult Index(ManageMessageId? smess)
{
var errorModel = new ErrorModel();
...
return CurrentTemplate(errorModel);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Index(ErrorModel model)
{
if (ModelState.IsValid)
{
...
}
return View();
}
Assuming you are using SurfaceControllers, you would want to create your form as follows. Note the change in how you create the form and how the generic and parameter match that of the surface controller:
#using (Html.BeginUmbracoForm<MyController>("Index"))
{
}
Your controller should look something like:
public class MyController : SurfaceController
{
public ActionResult Index(ManageMessageId? smess)
{
var errorModel = new ErrorModel();
...
return CurrentTemplate(errorModel);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Index(ErrorModel model)
{
if (ModelState.IsValid)
{
...
}
return View();
}
}

getting values View data in controller

i did this all but now how to get values being typed in Textbox, password box etc in CONTROLLER. I defined all necessary methods, boxes and buttons etc. So the only problem is to get values in controller and then to send them to model for accessing db data
.csHtml
#using (Html.BeginForm("register","Home", FormMethod.Post, new {id="submitForm"}))
{
<div>
<i>#Html.Label("Name:")</i>
#Html.TextBox("txtboxName")
</div>
<div>
<i>#Html.Label("Email:")</i>
#Html.TextBox("txtboxEmail")
</div>
<div>
<i>#Html.Label("Password:")</i>
#Html.Password("txtboxPassword")
</div>
<div>
<button type="submit" id="btnSubmit" name="Command" value="Submit">Submit</button>
</div>
}
Controller code:
namespace LoginSys.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.Message = "Registration";
return View();
}
[HttpPost]
public ActionResult register(string command, FormCollection formData )
{
if (command == "submit")
{
var name = formData["txtboxName"];
var email = formData["txtboxEmail"];
}
return View();
}
}
}
i'm intentionally using this way of coding it instead of complex and advance one. Just help me to get values in controller
[HttpPost]
public ActionResult register(YOURMODEL model)
{
//db operation
return View();
}
NOTE: make sure your textbox name should be same as your model name
You should use viewmodels. create a model for the view that can be posted to the action. However, if you wish to continue your current approach you need to change the controller action to something like this:
[HttpPost]
public ActionResult register(string btnSubmit, string txtboxName, string txtboxEmail, string txtboxPassword)
{
if (command == "submit")
{
}
return View();
}
if this doesn't work, you can test it by using this:
[HttpPost]
public ActionResult register(FormCollection form)
{
if (command == "submit")
{
}
return View();
}
When you debug you can check the 'form' parameter and see that your fields exists in the form, and get the proper names for the parameters you need.

How do I populate HTML content with new values once data has been changed on postback?

I have MVC3 razor application. Once I'm submitting a form and in Action i'm changing ViewModel content, i can't see new values populated.
There was a topic about that in MVC2 where guys told that it may be fixed in MVC3
http://aspnet.codeplex.com/workitem/5089?ProjectName=aspnet
Can you tell if there is an option to do that or what is the better way(workaround) to update UI without JavaScript using postbacks?
Action:
[HttpPost]
public ActionResult Index(MyViewModel model)
{
model.Value = "new value"
return View("Index", model);
}
UI:
#Html.HiddenFor(x => x.Value)
ViewModel:
public class MyViewModel
{
public string Value { get;set; }
}
Looks like it's using the ModelState values that were posted.
If you clear the ModelState using ModelState.Clear() the new value you set should be in the hidden field.
You should use form and to post it to action.
#model MyViewModel
#using (Html.BeginForm("Index", "Home", FormMethod.Post))
{
#Html.HiddenFor(x=>x.Value)
<input type="submit" value="Submit" />
}
Controller
//
public ActionResult Index()
{
MyViewModel model = new MyViewModel();
model.Value = "old value";
return View("Index", model);
}
[HttpPost]
public ActionResult Index(MyViewModel model)
{
//get posted model values (changed value by view "new value")
string changed_value = model.Value;
// you can return model again if your model.State is false or after update
return View("Index", model);
}

How do I create a httppost getting same parameters from httpget?

I have a controller to show up a model (User) and want to create a screen just with a button to activate. I don't want fields in the form. I already have the id in the url. How can I accomplish this?
Use [ActionName] attribute - this way you can have the URLs seemingly point to the same location but perform different actions depending on the HTTP method:
[ActionName("Index"), HttpGet]
public ActionResult IndexGet(int id) { ... }
[ActionName("Index"), HttpPost]
public ActionResult IndexPost(int id) { ... }
Alternatively you can check the HTTP method in code:
public ActionResult Index(int id)
{
if (string.Equals(this.HttpContext.Request.HttpMethod, "POST", StringComparison.OrdinalIgnoreCase))
{ ... }
}
A bit late to the party on this but I found an easier solution to what I think is a fairly common use-case where you prompt on GET ("are you sure you want to blah blah blah?") and then act on POST using the same argument(s).
The solution: use optional parameters. No need for any hidden fields and such.
Note: I only tested this in MVC3.
public ActionResult ActivateUser(int id)
{
return View();
}
[HttpPost]
public ActionResult ActivateUser(int id, string unusedValue = "")
{
if (FunctionToActivateUserWorked(id))
{
RedirectToAction("NextAction");
}
return View();
}
On a final note, you can't use string.Empty in place of "" because it must be a compile-time constant. And it's a great place to put funny comments for someone else to find :)
You could use a hidden field inside the form:
<% using (Html.BeginForm()) { %>
<%= Html.HiddenFor(x => x.Id) %>
<input type="submit" value="OK" />
<% } %>
or pass it in the action of the form:
<% using (Html.BeginForm("index", "home",
new { id = RouteData.Values["id"] }, FormMethod.Post)) { %>
<input type="submit" value="OK" />
<% } %>
My approach is not to add an unused parameter as that seems like it would cause confusion, and is in general bad practice. Instead, what I do is append "Post" to my action name:
public ActionResult UpdateUser(int id)
{
return View();
}
[HttpPost]
public ActionResult UpdateUserPost(int id)
{
// Do work here
RedirectToAction("ViewCustomer", new { customerID : id });
}
The easiest way for such simple situation is to give a name to submit button and check in action if it has value or not.
If it has the value, then it Post action, if not, then it Get action :
<% using (Html.BeginForm("index", "home",
new { id = RouteData.Values["id"] }, FormMethod.Post)) { %>
<input type="submit" value="OK" name="btnActivate" />
<% } %>
For Cs you can combine get and post controller methods in one:
public ActionResult Index(int? id, string btnActivate)
{
if (!string.IsNullOrEmpty(btnActivate))
{
Activate(id.Value);
return RedirectToAction("NextAction");
}
return View();
}

How do I redirect to the previous action in ASP.NET MVC?

Lets suppose that I have some pages
some.web/articles/details/5
some.web/users/info/bob
some.web/foo/bar/7
that can call a common utility controller like
locale/change/es or authorization/login
How do I get these methods (change, login) to redirect to the previous actions (details, info, bar) while passing the previous parameters to them (5, bob, 7)?
In short: How do I redirect to the page that I just visited after performing an action in another controller?
try:
public ActionResult MyNextAction()
{
return Redirect(Request.UrlReferrer.ToString());
}
alternatively, touching on what darin said, try this:
public ActionResult MyFirstAction()
{
return RedirectToAction("MyNextAction",
new { r = Request.Url.ToString() });
}
then:
public ActionResult MyNextAction()
{
return Redirect(Request.QueryString["r"]);
}
If you want to redirect from a button in the View you could use:
#Html.ActionLink("Back to previous page", null, null, null, new { href = Request.UrlReferrer})
If you are not concerned with unit testing then you can simply write:
return Redirect(ControllerContext.HttpContext.Request.UrlReferrer.ToString());
A suggestion for how to do this such that:
the return url survives a form's POST request (and any failed validations)
the return url is determined from the initial referral url
without using TempData[] or other server-side state
handles direct navigation to the action (by providing a default redirect)
.
public ActionResult Create(string returnUrl)
{
// If no return url supplied, use referrer url.
// Protect against endless loop by checking for empty referrer.
if (String.IsNullOrEmpty(returnUrl)
&& Request.UrlReferrer != null
&& Request.UrlReferrer.ToString().Length > 0)
{
return RedirectToAction("Create",
new { returnUrl = Request.UrlReferrer.ToString() });
}
// Do stuff...
MyEntity entity = GetNewEntity();
return View(entity);
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(MyEntity entity, string returnUrl)
{
try
{
// TODO: add create logic here
// If redirect supplied, then do it, otherwise use a default
if (!String.IsNullOrEmpty(returnUrl))
return Redirect(returnUrl);
else
return RedirectToAction("Index");
}
catch
{
return View(); // Reshow this view, with errors
}
}
You could use the redirect within the view like this:
<% if (!String.IsNullOrEmpty(Request.QueryString["returnUrl"])) %>
<% { %>
Return
<% } %>
In Mvc using plain html in View Page with java script onclick
<input type="button" value="GO BACK" class="btn btn-primary"
onclick="location.href='#Request.UrlReferrer'" />
This works great. hope helps someone.
#JuanPieterse has already answered using #Html.ActionLink so if possible someone can comment or answer using #Url.Action
I'm using .Net Core 2 MVC , and this one worked for me,
in the controller use
HttpContext.Request.Headers["Referer"];
Pass a returnUrl parameter (url encoded) to the change and login actions and inside redirect to this given returnUrl. Your login action might look something like this:
public ActionResult Login(string returnUrl)
{
// Do something...
return Redirect(returnUrl);
}
You could return to the previous page by using ViewBag.ReturnUrl property.
To dynamically construct the returnUrl in any View, try this:
#{
var formCollection =
new FormCollection
{
new FormCollection(Request.Form),
new FormCollection(Request.QueryString)
};
var parameters = new RouteValueDictionary();
formCollection.AllKeys
.Select(k => new KeyValuePair<string, string>(k, formCollection[k])).ToList()
.ForEach(p => parameters.Add(p.Key, p.Value));
}
<!-- Option #1 -->
#Html.ActionLink("Option #1", "Action", "Controller", parameters, null)
<!-- Option #2 -->
Option #2
<!-- Option #3 -->
Option #3
This also works in Layout Pages, Partial Views and Html Helpers
Related: MVC3 Dynamic Return URL (Same but from within any Controller/Action)
For ASP.NET Core
You can use asp-route-* attribute:
<form asp-action="Login" asp-route-previous="#Model.ReturnUrl">
Other in details example:
Imagine that you have a Vehicle Controller with actions
Index
Details
Edit
and you can edit any vehicle from Index or from Details, so if you clicked edit from index you must return to index after edit
and if you clicked edit from details you must return to details after edit.
//In your viewmodel add the ReturnUrl Property
public class VehicleViewModel
{
..............
..............
public string ReturnUrl {get;set;}
}
Details.cshtml
<a asp-action="Edit" asp-route-previous="Details" asp-route-id="#Model.CarId">Edit</a>
Index.cshtml
<a asp-action="Edit" asp-route-previous="Index" asp-route-id="#item.CarId">Edit</a>
Edit.cshtml
<form asp-action="Edit" asp-route-previous="#Model.ReturnUrl" class="form-horizontal">
<div class="box-footer">
<a asp-action="#Model.ReturnUrl" class="btn btn-default">Back to List</a>
<button type="submit" value="Save" class="btn btn-warning pull-right">Save</button>
</div>
</form>
In your controller:
// GET: Vehicle/Edit/5
public ActionResult Edit(int id,string previous)
{
var model = this.UnitOfWork.CarsRepository.GetAllByCarId(id).FirstOrDefault();
var viewModel = this.Mapper.Map<VehicleViewModel>(model);//if you using automapper
//or by this code if you are not use automapper
var viewModel = new VehicleViewModel();
if (!string.IsNullOrWhiteSpace(previous)
viewModel.ReturnUrl = previous;
else
viewModel.ReturnUrl = "Index";
return View(viewModel);
}
[HttpPost]
public IActionResult Edit(VehicleViewModel model, string previous)
{
if (!string.IsNullOrWhiteSpace(previous))
model.ReturnUrl = previous;
else
model.ReturnUrl = "Index";
.............
.............
return RedirectToAction(model.ReturnUrl);
}

Resources