ActionRequest hopping - asp.net-mvc

I have been working with controllers for a while and everything is working really great.
Until now!
My current scenario is that I have is a view that contains a button which triggers JavaScript code.
That JS code then triggers a method of a controller. And here I have an if condition that returns the view or does a RedirectToAction to another controller's method, which returns a view.
When pressing that button, I see in the debugger that my code runs through all those methods, when when it comes to returning the view, nothing happens.
Below is a simplified version of my code:
<script>
jQuery.ajax({
type: "POST",
url: "#Url.Action("applyChanges", "Controller1")",
data: { jsondata: config}
});
</script>
public class Controller1: Controller {
public ActionResult applyChanges(string jsondata)
{
return RedirectToAction("validateData", "Controller2", new { id = account.id});
}
}
public class Controller2: Controller
{
public ActionResult validateData(int id)
{
if(data.stored.under.this.id == false)
{
return View("validateData");
}
else
{
return RedirectToAction("viewList", "PMGLists", new { id = id });
}
}
}
The browser simply stays as if nothing happened.
What am I missing here?

Related

Controller name being lost when trying to post to controller action after file upload

I have a MVC Controller which contains a couple of actions. One action is responsible for changing rate. Another one is responsible for uploading a file.
the actions work correctly when I play with them. but as soon as I upload a file, if I try to change the rate the post action fails because the url it tries to post to lack the controller name in it. Here are the codes.
here is my code in the view:
Change rate:
<form method="post" action="#Url.Action("UploadPreparedContract")">
#Html.Hidden("userApplicationId", Model.UserApplicationId)
<div class="upload-section k-content">
#Html.Kendo().Upload().Name("files")
<input type="submit" value="Submit"/>
</div>
</form>
<script type="text/javascript">
jQuery(function($) {
var viewModel = kendo.observable({
currentDisclosedRate: "#Model.CurrentDisclosedRate",
changeRate: function(e) {
e.preventDefault();
var self = this;
var rawValue = $('#newDisclosureRate').val();
var rate = parseFloat(rawValue);
$.ajax({
type: "POST",
url: 'ChangeDisclosureRate',
data: { newRate: rate, userApplicationId: #Model.UserApplicationId},
}).done(function(result) {
Notification.success('Rate changed');
self.set("currentDisclosedRate", rawValue);
})
.fail(function(err) {
Notification.error('Not changed. Customer may have placed order');
});
},
});
kendo.bind($("#page"), viewModel);
});
and here is the controller
public class ContractPreparationController : Controller
{
// GET: Application/ContractPreparation
public ActionResult Index(int userApplicationId)
{
// logic to prepare model
return View(new ContractPreparationOutputModel()
{
// Model properties
});
}
[HttpPost]
public async Task<ActionResult> ChangeDisclosureRate(decimal newRate, int userApplicationId)
{
return await Command.ApplyAsync(new ChangeDisclosureRateCommand() {UserApplicationId = userApplicationId, NewDisclosureRate = BasisPoint.Percent(newRate) }) == Command.CommandResult.Succeeded
? new HttpStatusCodeResult(HttpStatusCode.OK)
: new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
[HttpPost]
public async Task<ActionResult> UploadPreparedContract(IEnumerable<HttpPostedFileBase> files, int userApplicationId)
{
if (files == null)
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
if (files.Count() != 1)
return new HttpStatusCodeResult(HttpStatusCode.BadRequest, "You must upload one file only");
var application = applicationRepository.GetUserApplication(userApplicationId);
if (application == null)
return new HttpStatusCodeResult(HttpStatusCode.BadRequest, "Invalid user");
var file = files.Single();
var memberDocument = new MemberDocument(blobService, application.FK_UserId);
await memberDocument.Uploadfile(file);
if (await Command.ApplyAsync(new UploadPreparedContractCommand() {FileGuid = memberDocument.FileGuid , UserApplicationId = userApplicationId, FileExtension = memberDocument.FileExtension}) == Command.CommandResult.Succeeded)
{
return RedirectToAction("Index", new {userApplicationId});
}
return new HttpStatusCodeResult(HttpStatusCode.InternalServerError); // No expected failure case
}
}
Use the Url.Action helper method to generate the correct relative url to the action method.
url: '#Url.Action("ChangeDisclosureRate","ContractPreparation")',
When razor executes the code for your view, it will run the Url.Action method and output the correct url (which will have the controller name if needed). You can see it if you do view source of the page.
Try adding the controller name to your ajax url parameter:
url: 'ContractPreparation/ChangeDisclosureRate'
Otherwise MVC doesn't know what controller to use.

View not refreshing after AJAX post

I have a view (Index.cshtml) with a grid (Infragistics JQuery grid) with an imagelink. If a user clicks on this link the following jquery function will be called:
function ConfirmSettingEnddateRemarkToYesterday(remarkID) {
//Some code...
//Call to action.
$.post("Home/SetEnddateRemarkToYesterday", { remarkID: remarkID }, function (result) {
//alert('Succes: ' + remarkID);
//window.location.reload();
//$('#remarksgrid').html(result);
});
}
Commented out you can see an alert for myself and 2 attempts to refresh the view. The location.reload() works, but is basically too much work for the browser. The .html(result) posts the entire index.cshtml + Layout.cshtml double in the remarksgrid div. So that is not correct.
This is the action it calls (SetEnddateRemarkToYesterday):
public ActionResult SetEnddateRemarkToYesterday(int remarkID) {
//Some logic to persist the change to DB.
return RedirectToAction("Index");
}
This is the action it redirects to:
[HttpGet]
public ActionResult Index() {
//Some code to retrieve updated remarks.
//Remarks is pseudo for List<Of Remark>
return View(Remarks);
}
If I don't do window.location.reload after the succesfull AJAX post the view will never reload. I'm new to MVC, but i'm sure there's a better way to do this. I'm not understanding something fundamental here. Perhaps a nudge in the right direction? Thank you in advance.
As you requesting AJAX call, you should redirect using its response
Modify your controller to return JSONResult with landing url:
public ActionResult SetEnddateRemarkToYesterday(int remarkID) {
//Some logic to persist the change to DB.
var redirectUrl = new UrlHelper(Request.RequestContext).Action("Index", "Controller");
return Json(new { Url = redirectUrl });
}
JS Call:
$.post("Home/SetEnddateRemarkToYesterday", { remarkID: remarkID }, function (result) {
window.location.href = result.Url
});
After Ajax post you need to call to specific Url..
like this..
window.location.href = Url
When using jQuery.post the new page is returned via the .done method
jQuery
jQuery.post("Controller/Action", { d1: "test", d2: "test" })
.done(function (data) {
jQuery('#reload').html(data);
});
HTML
<body id="reload">
For me this works. First, I created id="reload" in my form and then using the solution provided by Colin and using Ajax sent data to controller and refreshed my form.
That looks my controller:
[Authorize(Roles = "User")]
[HttpGet]
public IActionResult Action()
{
var model = _service.Get()...;
return View(model);
}
[Authorize(Roles = "User")]
[HttpPost]
public IActionResult Action(object someData)
{
var model = _service.Get()...;
return View(model);
}
View:
<form id="reload" asp-action="Action" asp-controller="Controller" method="post">
.
.
.
</form>
Javascript function and inside this function I added this block:
$.ajax({
url: "/Controller/Action",
type: 'POST',
data: {
__RequestVerificationToken: token, // if you are using identity User
someData: someData
},
success: function (data) {
console.log("Success")
console.log(data);
var parser = new DOMParser();
var htmlDoc = parser.parseFromString(data, 'text/html'); // parse result (type string format HTML)
console.log(htmlDoc);
var form = htmlDoc.getElementById('reload'); // get my form to refresh
console.log(form);
jQuery('#reload').html(form); // refresh form
},
error: function (error) {
console.log("error is " + error);
}
});

Calling RedirectToAction

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.

How to return back a message after a submit

I have the following code which is not working as expected. I want to have a retrun from the controller and using alert display the value returned from the controller.
$('#change').dialog({
autoOpen: false,
width: 380,
buttons: {
"Close": function() {
$(this).dialog("close");
},
"Accept": function() {
var test = $("#ChangePasswordForm").submit();
alert(test);
}
}
});
In my controller I want to return a string
[AcceptVerbs(HttpVerbs.Post)]
public string ChangePassword(string Name)
{
var msg = "Cool!";
if (name != null)
return msg;
}
How can I do that?
Your controller needs to return a type that derives from an ActionResult.
If you want to display a simple confirmation message you can add it to the ViewData bag like this:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult ChangePassword(string name)
{
if (!string.IsNullOrEmpty(name))
{
ViewData["msg"] = "Cool";
}
return View();
}
Then, in your view, check for the presence of the value, and display it if it's there:
<% if(ViewData["msg"] != null) { %>
<script type="text/javascript">alert('<%= ViewData["msg"].ToString() %>')</script>
<%} %>
First of all, im assuming you are using an ajax form for this. I also assume you have a or something for putting your text into. All you have to do is set the UpdateTargetId to point at the id of the element you want to update with the text
<%using (Ajax.Form("ChangePasswordForm", new AjaxOptions { UpdateTargetId = "result" })) %>
.
[HttpPost]
public ContentResult ChangePassword(string s)
{
var msg = "Cool!";
if ( s != null ? return Content(msg, "text/plain") : return Content("An error has occured", "text/plain") );
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult ChangePassword(string Name)
{
var msg = "Cool!";
if (name != null)
{
return Content(msg, "text/plain");
}
else
{
return Content("Error...", "text/plain");
}
}
Don't submit the form as that will perform a postback and cause the dialog to be removed.
Instead perform an AJAX post to the Controller Action and return a JsonResult containing the data.
Hook into the success callback from the Ajax request, and call alert passing the data from the Json object.
You'll probably wan't to use a loading mask after clicking submit so the user knows something is going on.

ASP.NET MVC with jQuery

I'm currently attempting to retrieve a list of objects from my database using jQuery. I have been attempting to use getJSON but the callback is never fired. However, if I use
$.post(url, data, callback)
... then it seems to fire just fine.
My controller actions is thus:
public ActionResult GetTemplates()
{
IEnumerable<Template> templates = TemplateDAO.GetTemplates();
List<TemplateViewModel> jsonTemplates = new List<TemplateViewModel>();
foreach(Template t in templates)
{
TemplateViewModel tvm = new TemplateViewModel(t.ID, t.TemplateName);
jsonTemplates.Add(tvm);
}
return Json(jsonTemplates.ToList());
}
and the TemplateViewModel is:
public class TemplateViewModel
{
public int ID {get; set; }
public string TemplateName {get; set; }
}
The javascript I'm attempting to use is:
function LoadTemplates() {
alert("loading templates");
var url = '<%= Url.Action("GetTemplates", "Project") %>';
$.getJSON(url, null, function(data) {
alert("Succeeded" + data);
});
}
This javascript does not show the "Succeeded" alert for some reason, whereas replacing the getJSON call with
$.post(url, null, updateTemplates, 'json');
works.
Any ideas?
It's more of a curiosity thing now that $.post works, but I'd like to know what I'm doing wrong, as every example I've seen looks exactly like mine!
Cheers,
Chris
Try this:
return Json(jsonTemplates.ToList(), JsonRequestBehavior.AllowGet);

Resources