Calling RedirectToAction - asp.net-mvc

I have a form that calls this action to build the CompareEvents page:
[HttpPost]
public ActionResult CompareEvents(int[] EventsList, bool showIndex, bool showFRN, bool showProvider)
{
var viewModel = new EventsListViewModel
{
Events = EventsList,
ShowFRN = showFRN,
ShowIndex = showIndex,
ShowProvider = showProvider
};
return View(viewModel);
}
in the CompareEvents view there is another form that allows the user to update information:
[HttpPost]
public ActionResult UpdateSolution(IEnumerable<Solution> sol)
{
//update solution code
int[] eventList = { '85' };
return RedirectToAction("CompareEvents", new { EventsList = eventList, showIndex = true, showFRN = true, showProvider = true });
}
When this information is update, I would like to reload the page. I plan on doing this by calling the CompareEvents action again, however my stacktrace is saying that A public action method 'CompareEvents' was not found on controller
How can I accomplish this?

You cannot redirect to an action that is marked [HttpPost]. RedirectToAction uses a GET.
Source:
Returns an HTTP 302 response to the browser, which causes the browser to make a GET request to the specified action.
Reference.

Related

MVC, cannot return to the previous URL

I am working on some legacy code.
I have a form which I edit some data and when I click save, if successful I want to return to the previous form.
So my controller methods are;
public ActionResult Edit(int callDiaryId)
{
ViewBag.PreviousUrl = System.Web.HttpContext.Current.Request.UrlReferrer;
var callDiary = this.SCDCallDiaryRepository.Get(callDiaryId);
return this.View("Edit", new DiaryItemViewModel(callDiary));
}
[HttpPost]
[ValidateAntiForgeryToken]
[ValidateOnlyIncomingValuesAttribute]
public ActionResult Edit(DiaryItemViewModel item, string previousUrl)
{
var callDiary = this.SCDCallDiaryRepository.Get(item.SCD_CallDiaryId);
callDiary.Comments = item.Comments;
callDiary.ContractId = item.ContractId;
var opStatus = this.SCDCallDiaryRepository.Update(callDiary);
if (opStatus.Status)
{
this.TempData["SuccessMessage"] = "Details updated successfully.".MessageTime();
return RedirectToAction(previousUrl);
}
this.TempData["ErrorMessage"] = "Details NOT updated.".MessageTime();
ViewBag.PreviousUrl = previousUrl;
return this.View(new DiaryItemViewModel(callDiary));
}
and the incoming value of previousUrl is
http://localhost:58384/LogDiary/Comments?companyId=11033
This works perfectly for my back button.
But after my RedirectToAction command is performed, the Bad Request error that I get is because the Url it is showing is;
http://localhost:58384/LogDiary/http%3a/localhost%3a58384/LogDiary/Comments%3fcompanyId%3d11033
How do I fix this?
I was able to do this in the Controller of my App to return the user to the previous page
public ActionResult ChangePassword()
{
var userId = this.User.Identity.GetUserId();
var viewModel = this._userService.ChangePasswordViewModelForUser(userId);
viewModel.PreviousPage = this.Request.UrlReferrer.AbsoluteUri;
return this.View(viewModel);
}
If I need to use it in a button
#Resource.Button_Cancel
I think I found the answer.
Instead of using RedirectToAction, I am now using Redirect.
You can return to the previous form by doing the below code
[HttpPost]
[ValidateAntiForgeryToken]
[ValidateOnlyIncomingValuesAttribute]
public ActionResult Edit(DiaryItemViewModel item)
{
..your other code..
return View(item);
}
it will return to the Edit page along with the entered data
hope this helps

HTTPPOST Attribute not working in MVC

i have a Controller in which two actions are defined.
public class ExamlpeController : Controller
{
[Route("Index")]
public ActionResult Index()
{
return View(new ExampleViewModel { Message = new MessageDisplay { MessageVisible = false, IsGoodMessage = true, Message = String.Empty } });
}
// POST:
[HttpPost]
[Route("Index/{exampleData?}")]
public ActionResult Index(ExampleViewModel exampleData)
{
if (!ModelState.IsValid) // If model state is invalid
// Return view with validation summary
return View(new ExampleViewModel { Message = new MessageDisplay { MessageVisible = false, IsGoodMessage = true, Message = String.Empty } });
else // If model state is valid
{
// Process further
bool isGoodMessage = true; // Default
string message = "success";
isGoodMessage = true;
message = "test data";
// Clear model state if operation successfully completed
if (isGoodMessage)
ModelState.Clear();
return View(new ExampleViewModel { Message = new MessageDisplay { IsGoodMessage = isGoodMessage, MessageVisible = true, Message = message } });
}
}
}
so, when my view is called then first "Index" action is called but when i post my form it also called first index method.
this code is working fine in old build, new build contains some changes which are not related to this Controller, but it is not working,
when i add HTTPGET Attribute with first action then it is working fine,
first action called on page load and second action is called on page post.
so, my question is that how Routes are maintained the route table and what is the reason for that condition.
On your POST action change [Route("Index/{exampleData?}")] to [Route("Index")] and it should work. You don't include the POSTed view model as part of the route - think about it, how would it display that posted data in the URL anyway?

View doesn't refresh after RedirectToAction is done

Here is my problem:
[HttpPost]
public ActionResult AddData(CandidateViewModel viewModel)
{
var newCandidateId = 0;
newCandidateId = this._serviceClient.AddCandidate(viewModel);
return RedirectToAction("DisplayCandidate",new {id=newCandidateId});
}
public ActionResult DisplayCandidate(int id)
{
var candidateViewModel= this._serviceClient.GetCandidate(id);
return View(candidateViewModel);
}
After filling the form viwemodel sends to server. After data were stored, flow is redirected to DisplayCandidate action and it goes there but page didn't refresh. I don't understand why! Help, please.
Because you are using Ajax Post
public ActionResult AddData(CandidateViewModel viewModel)
{
var newCandidateId = 0;
newCandidateId = this._serviceClient.AddCandidate(viewModel);
string ReturnURL = "/DisplayCandidate/"+newCandidateId;
return JSON(ReturnURL);
}
and in your Ajax Post Method:
Onsuccess(function(retURL){ window.location(retURL); })
This will take to the new Action and that Action will return View.
If you're using Ajax, return a script results to execute the navigation
instead of
return RedirectToAction("DisplayCandidate",new {id=newCandidateId});
try
var viewName = "/Path/ViewName";
var id = 1;
var urlNavigate = string.Format("location.href='{0}?id={1}'", viewName, id);
return new JavaScriptResult() { Script = urlNavigate };

ASP.NET MVC: Server Validation & Keeping URL paramters when returning the view

I currently have the following code for the POST to edit a customer note.
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult EditNote(Note note)
{
if (ValidateNote(note))
{
_customerRepository.Save(note);
return RedirectToAction("Notes", "Customers", new { id = note.CustomerID.ToString() });
}
else
{
var _customer = _customerRepository.GetCustomer(new Customer() { CustomerID = Convert.ToInt32(note.CustomerID) });
var _notePriorities = _customerRepository.GetNotePriorities(new Paging(), new NotePriority() { NotePriorityActive = true });
IEnumerable<SelectListItem> _selectNotePriorities = from c in _notePriorities
select new SelectListItem
{
Text = c.NotePriorityName,
Value = c.NotePriorityID.ToString()
};
var viewState = new GenericViewState
{
Customer = _customer,
SelectNotePriorities = _selectNotePriorities
};
return View(viewState);
}
}
If Validation fails, I want it to render the EditNote view again but preserve the url parameters (NoteID and CustomerID) for something like this: "http://localhost:63137/Customers/EditNote/?NoteID=7&CustomerID=28"
Any ideas on how to accomplish this?
Thanks!
This action is hit by using a post. Wouldn't you want the params to come through as part of the form rather than in the url?
If you do want it, I suppose you could do a RedirectToAction to the edit GET action which contains the noteId and customerId. This would effectively make your action look like this:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult EditNote(Note note)
{
if (ValidateNote(note))
{
_customerRepository.Save(note);
return RedirectToAction("Notes", "Customers", new { id = note.CustomerID.ToString() });
}
//It's failed, so do a redirect to action. The EditNote action here would point to the original edit note url.
return RedirectToAction("EditNote", "Customers", new { id = note.CustomerID.ToString() });
}
The benefit of this is that you've removed the need to duplicate your code that gets the customer, notes and wotnot. The downside (although I can't see where it does it here) is that you're not returning validation failures.

asp.net mvc custom exception filter to force a return of full view, not partial

I have a custom exception filter that I'm calling by virtue of adding a [CustomExceptionFilter] attribute to my class. It works as I'd like it to, however if the action method is returning a partial view (through an ajax request), the exception (which is basically a redirect to a not authorized page), is loading up the partial view with that page. Is there a way I can force it to reload the 'parent' url?
Here is the code for the custom exception filter
public class CustomExceptionFilter : FilterAttribute, IExceptionFilter
{
public void OnException(ExceptionContext filterContext)
{
if (filterContext.Exception.GetType() == typeof(CustomSecurityException))
{
filterContext.ExceptionHandled = true;
RequestContext rc = new RequestContext(filterContext.HttpContext, filterContext.RouteData);
string url = RouteTable.Routes.GetVirtualPath(rc, new RouteValueDictionary(new { Controller = "NoAccess", action = "Index", message = filterContext.Exception.Message })).VirtualPath;
filterContext.HttpContext.Response.Redirect(url, true);
}
}
}
This is something you need to handle on the browser. Try handling the error() on jQuery.ajax() call for example (and obviously don't return redirect..).
I would suggest letting the exception bubble up to the client and handle it like Maxwell suggested.
In our previous project we used a specific actionfilter for handling ajax errors (borrowed from Suteki Shop). Note that the response status is 500 (internal server error). An error status is required for the response in order to call de Error() delegate within a JQuery.ajax() call.
public class HandleErrorWithAjaxAttribute : HandleErrorAttribute
{
public HandleErrorWithAjaxAttribute()
{
ShowStackTraceIfNotDebug = true;
}
public bool ShowStackTraceIfNotDebug { get; set; }
public override void OnException(ExceptionContext filterContext)
{
if (filterContext.HttpContext.Request.IsAjaxRequest())
{
string content = ShowStackTraceIfNotDebug ||
filterContext.HttpContext.IsDebuggingEnabled
?
filterContext.Exception.StackTrace
:
string.Empty;
filterContext.Result = new ContentResult
{
ContentType = MediaTypeNames.Text.Plain,
Content = content
};
filterContext.HttpContext.Response.Status =
"500 " + filterContext.Exception.Message
.Replace("\r", " ")
.Replace("\n", " ");
filterContext.ExceptionHandled = true;
filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
}
else
{
base.OnException(filterContext);
}
}
}
I use the OnFailure hanlder in form tag.
<form id="AJAXForm" method="post" action=""
onsubmit="Sys.Mvc.AsyncForm.handleSubmit(this, new Sys.UI.DomEvent(event),
{ insertionMode: Sys.Mvc.InsertionMode.replace, httpMethod: 'POST',
updateTargetId: 'myPartialPage', onSuccess: Function.createDelegate(this, ajaxFormSucced),
onFailure: Function.createDelegate(this, ajaxFormFailure) });" >
...
function ajaxFormSucced(){
// Code for success
}
function ajaxFormFailure(){
// Code for failure
}
You can verify if the request is an ajax request or not.
You could for example do the following...
if (!filterContext.HttpContext.Request.IsAjaxRequest()){
//Return a ViewResult
//filterContext.ExceptionHandled = true;
//filterContext.Result = new ViewResult { ViewName = "Error" ... };
}
else{
//An ajax request.
//return a partial view
}
However, as Maxwell said you could let the exeption bubble up if it is an ajax request and handle the error on the client. You can setup globally a way of handling exceptions in ajax requests like it is described here
Did you try clearing the response? The controller may still be setting response content.
filterContext.HttpContext.Response.Clear()
filterContext.Result = new JsonResult { Data = new { Message = message } };
filterContext.HttpContext.Response.StatusCode = 500;
filterContext.ExceptionHandled = true;
filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
This link helped me
Handling ASP.NET MVC exceptions when posting to the controller via Ajax using jQuery
Lastly, When testing the javascript function, start with alert on the first line. Any javascript errors in your function are likely to stop the function in mid execution without javascript error feedback via the browser (depending on your setup).
This will help you.
Just add .IsAjaxRequest extension method and return 403 status code to browser, jquery ajaxError will handle it redirecting to login page
As Maxwell says, handle on the client, using something like this
function handleError(ajaxContext) {
// Load parent
}
#using (Ajax.BeginForm("Index", "Home", new AjaxOptions
{
UpdateTargetId = "MyDiv",
OnFailure = "handleError"
}))
What you must do though is make sure in the controller ActionResult code for NoAccess contains the following code, so that your ajax error is triggered.
HttpContext.Response.StatusCode = 401;

Resources