MVC Action receives wrong parameter via Jquery AJAX request - javascript

I am trying to be familiar with ASP MVC by working on simple MVC project.
But there is a problem I can't figure out.
On certain event, AJAX request is sent to one action taking IDictionary type parameter.
But the received parameter contains controller name, action name and language instead of data specified in Jquery AJAX call.
Please take a look at below code.
RouterConfig
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Language",
url: "{lang}/{controller}/{action}/{id}",
defaults: new {controller = "Login", action="Index", id=UrlParameter.Optional},
constraints: new {lang = #"en|fr"}
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Login", action = "Index", id = UrlParameter.Optional, lang = "en" }
);
}
Action
public ActionResult ApproveUsers(IDictionary<string, string> CheckedUsers)
{
return View();
}
JQuery
$('#confirmModal #action').click(function () {
var cb = {};
var data = {};
$("input:checkbox:checked").each(function () {
var key = $(this).attr('value');
var val = $(this).closest('tr').next().find('table').attr('id');
cb[key] = val;
});
$.ajax({
type: "POST",
url: '/AdminHome/ApproveUsers',
dataType: "html",
contentType: 'application/json',
data : JSON.stringify(cb),
success: function (result) {
alert("success");
},
error: function(result) {
alert("failed");
}
});
});
So when button is clicked all the checked checkbox data are sent to ApproveUsers action as keyvaluepair.
But no matter what the cb object in Jquery contains, the IDictionary parameter in ApproveUsers action only is like below
[0] {[ contoller, AdminHome ]}
[1] {[ action, ApproveUsers ]}
[2] {[ lang, en]}
This seems like there is something wrong with RouteConfig. But I don't know why.
I would really appreciate if anyone can help me know why and fix this issue.
Thanks,

I found what's wrong with my code.
I was missing the parameter name in AJAX call so parameter biding failed.
As Steve said, code should be like below.
data : JSON.stringify(CheckedUsers:cb)

Related

Passing parameters in Ajax post back in MVC

I am trying to pass ID parameter from a view to a controller on a click delete link available on a selected row.
Simplified View Layout
#using (Html.BeginForm("#", "Schedule", FormMethod.Post, htmlAttributes: new { #class = "floating-labels" }))
{
#Html.AntiForgeryToken()
Delete
}
JavaScript
<script type="text/javascript">
function DeleteSchedule(id) {
if (confirm('Are you sure you want to delete this Schedule?')) {
$.ajax({
type: "POST",
url: '#Url.Action("Delete", "Schedule", new { id = "id" })',
contentType: "application/json",
data: { id },
async: true,
cache: false,
success: function (result) { success(result); }
});
}
return false;
}
function success(result) {
$("#ScheduleList").html(result);
}
</script>
Controller
namespace Controllers
{
public class ScheduleController
{
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Delete(int id)
{
//do stuff
}
}
}
But on the click of a delete link I get below error and code does not hit controller action.
I am not able to figure out what mistake I am making...
Here is my locally tested implementation that is working.
ScheduleController class:
public class ScheduleController : Controller
{
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Delete(int id)
{
return Ok(id);
}
}
Page that sends the post request:
#Html.AntiForgeryToken()
Delete
<div id="ScheduleList"></div>
<script>
function DeleteSchedule(id) {
if (confirm('Are you sure you want to delete this Schedule?')) {
var uri = '/Schedule/Delete?id=' + id;
var tokenElement = document.getElementsByName('__RequestVerificationToken')[0];
var data = {
__RequestVerificationToken: tokenElement.value
}
$.ajax({
type: "POST",
url: uri,
data: data,
success: function (result) {
success(result);
}
});
}
return false;
}
function success(result) {
$("#ScheduleList").html(result);
}
</script>
The page does nothing but render the html, and the javascript handles the actual Ajax post. What I believe you were missing is the Validation token in your request.
It is because you are not actullay posting the form pass it correctly and add _token in the ajax data list and value for that token will come from #Html.AntiforgeryToken()
reading the error the request is most probably send correctly and there is an internal server error as mentioned in the 500 respond so please check the code that is inside the controller
Try this, you are accesing a javascript variable on c# code, and you cant do that.
If correct, please mark as answer.
function DeleteSchedule(id) {
if (confirm('Are you sure you want to delete this Schedule?')) {
var url = '#Url.Action("Delete", "Schedule")?id=' + id;
$.ajax({
type: "POST",
url: url,
contentType: "application/json",
data: { id },
async: true,
cache: false,
success: function (result) { success(result); }
});
}
return false;
}
I think none of the answers above solve the issue. First of all I would replace your target url:
url: '#Url.Action("Delete", "Schedule", new { id = "id" })',
with
url: '#Url.Action("Delete", "Schedule", new { id = actualIdVariable })',
(replace "id" with the actual id variable from the model you're passing to the view).
Note how your browser response is telling you that the url you're posting to is Schedule/Delete/id. That said, I'm not sure you even need the routeValues in this case (the new { id = ...} parameter). this is a POST action, and action parameters wouldn't come from route unless specified by by attribute routing (i.e. [Route("~/Schedule/Delete/{id}")] attribute on your action).
I think your post action is failing because it is trying to parse the "id" string as an int.
Second, I would change the data property of the ajax call and include the anti forgery token. Just because the anchor element you're binding the click event to, is inside the form with #Html.AntiforgeryToken() doesn't mean the generated token will be posted in the ajax request. You're not actually submitting/posting the form, you're just clicking a button.
it should be something like
data: {
'id': id,
'__RequestVerificationToken': $('[name="__RequestVerificationToken"]').val()
}
try this, it solve the error on routing (different url Action) and the parameter on the controller:
JavaScript
<script type="text/javascript">
function DeleteSchedule(id) {
if (confirm('Are you sure you want to delete this Schedule?')) {
$.ajax({
type: "POST",
url: '#Url.Action("Delete", "Schedule")',
data: "id=" + id ,
async: true,
cache: false,
success: function (result) { success(result); }
});
}
return false;
}
function success(result) {
$("#ScheduleList").html(result);
}
</script>
Controller:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Delete(string id)
{
//do stuff
}
Nicola.

How to do an ajax post, from javascript, to a web-api service

I'm trying to make a logging method, that works on all my javascript calls.
It is not going too well. I get the following error:
No action was found on the controller 'Log' that matches the request.
I have the following code, on my controller:
[System.Web.Mvc.HttpPost]
public void Post(string msg)
{
using (var ctx = new DataClassesDataContext(ConfigurationManager.ConnectionStrings["EasyViewDkConnectionString"].ToString()))
{
ctx.UserInputInsert(msg, HttpContext.Current.Request.UserHostAddress);
}
}
VERY simple. I am a bit unsure if it my routing that is the problem. Basically, I just have the default route:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
To post the data, I'm using this javascript:
function Log(msg) {
$.ajax({
url: "/api/Log/",
data: msg,
type: "POST",
contentType: "application/json;charset=utf-8"
});
}
So obviously, I'm doing something wrong. It is probably my routing, but I can't seem to solve it. I have tried changing the msg argument on the controller, to id, but it's still the same.
I've been googling around for a while now, and I stumbled upon this article:
http://encosia.com/using-jquery-to-post-frombody-parameters-to-web-api/
It turns out, web Api doesn't really like it when you post a primitive value, like a string. To get it to work, you need to add [FromBody]to the parameter and also have a blank value name, when posting.
So, I have changed my code around a bit, and it now looks like this, and works.
Javascript:
function Log(msg) {
$.post("/api/Log", { "": msg });
}
And my controller:
[System.Web.Http.HttpPost]
public HttpResponseMessage Post([FromBody]string value)
{
using (var ctx = new DataClassesDataContext(ConfigurationManager.ConnectionStrings["EasyViewDkConnectionString"].ToString()))
{
ctx.UserInputInsert(value, HttpContext.Current.Request.UserHostAddress);
}
return new HttpResponseMessage(HttpStatusCode.OK);
}
Another possibility that has worked for me in the past...
You may possibly consider changing your mapping to include the controller action
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
Then change your url in the ajax method to [controller]/[method]/. You would also need to define your post data argument.
$.ajax({
url: "/api/Log/Post/", //--'Log' being the Controller, 'Post' being the method
data: JSON.stringify({"msg":msg}),
type: "POST",
contentType: "application/json;charset=utf-8"
});
Hope that helps. Keep us posted!

MVC 4 APIController not receiving POST data

Sure this had been dealt with many times... but.. just cant see what im doing wrong!
This is a simple JS script that Posts data back to ApiController.
function WebCall(url,parameterObject, callBackFunction) {
this.callbackfunction = callBackFunction;
this.parameterObject = parameterObject;
this.url = url;
self = this;
this.GetData = function () {
//self = this;
$.ajax({
//dataType: "json",
type: "POST",
url: self.url,
data: JSON.stringify(self.parameterObject),
contentType: "application/json;charset=utf-8",
success: function (data) {
self.callbackfunction.call(this, data);
},//self.GotData,
error: function (xhRequest, ErrorText, thrownError)
{
alert("error : " + ErrorText)
},
complete: function () {},
})
}
}
The data being sent (parameterObject) is simply
var postData = {
clientId: id
}
The c# code in the controller is :
public class ClientPostObject
{
public string clientId;
}
public class ClientDetailController : ApiController
{
[HttpPost]
public ClientDetailWidgetData GetClient(ClientPostObject clientObject)
{
return new ClientModel().GetClientDetail(clientObject.clientId);
}
}
In Google chrome developer tools, the XHR is showinf 'form Data' as clientId:A0001 - so that looks ok?
No matter what I try (and I'be been through many suggestions on the web), the post data is not there.
Sure its something simple.... Thanks in advance.
Unless you're planning on using a full-on form to submit to this method at some other point, it doesn't really make sense to ask the model binder to attempt to bind to a complex type when you're just using one property. Change your method signature to:
[HttpPost]
public ClientDetailWidgetData GetClient(int clientId) // or whatever type clientId represents
{
return new ClientModel().GetClientDetail(clientId);
}
I'd also recommend adding Glimpse at some point (http://getglimpse.com/) so that you can see how the model binding and/or routing of your app works.
Try to ditch contentType and don't stringify data:
$.ajax({
type: "POST",
url: self.url,
data: self.parameterObject,
success: function (data) {...},
...
});

Javascript url action in razor view

I have a javascript method onRowSelected wchich gets rowid. How to pass the rowid in certain action of a controller with HttpGet?
function onRowSelected(rowid, status) {
alert('This row has id: ' + rowid);
//url: #Action.Url("Action","Controller")
//post:"GET"
// Something like this?
}
If your controller action expects an id query string parameter:
var url = '#Url.Action("Action", "Controller")?id=' + rowid;
or if you want to pass it as part of the route you could use replace:
var url = '#Url.Action("Action", "Controller", new { id = "_id_" })'
.replace('_id_', rowid);
yet another possibility if you are going to send an AJAX request is to pass it as part of the POST body:
$.ajax({
url: '#Url.Action("Action", "Controller")',
type: 'POST',
data: { id: rowid },
success: function(result) {
}
});
or as a query string parameter if you are using GET:
$.ajax({
url: '#Url.Action("Action", "Controller")',
type: 'GET',
data: { id: rowid },
success: function(result) {
}
});
All those suppose that your controller action takes an id parameter of course:
public ActionResult Action(string id)
{
...
}
So as you can see many ways to achieve the same goal.
The method by Darin will work fine and perfectly.
I would suggest one more way for Razor view to use model value using #Html.actionlink in jsp
var URLvalue='#Html.ActionLink("UserString", "action", new { routeValueName1 = "__value1__", routeValueName2="__value2__" }, htmlAttributes: new { #class = "btn btn-default", #role = "button" })'
.replace('__value1__', Model.somevalue).replace('__value2__', Model.somevalue);
you can use URLvalue where ever you want to in jsp or jquery.

Jquery ajax post to MVC2 action

I'm using the following script to post to and endpoint, it's hitting the breakpoint on the server so I know the routing is correct.
$(document).ready(function() {
var o = new Object();
o.message = 'Hi from the page';
$.ajax({
type: 'POST',
contentType: 'application/json;',
data: JSON.stringify(o),
dataType: 'json',
url: 'home/PingBack',
success: function(result) {
alert(result.success);
}
});
});
The endpoint on the server looks like this.
public JsonResult PingBack(MHolder message)
{
return Json(new { success = "steve"});
}
and the Model looks like this.
public class MHolder
{
public string message { get; set; }
}
I'm sure that in the past the values have been automatically bound to the model, but I can't seem to get anything to be bound atm! Even if I just pass the value as a string, I'm sure it's something silly that I'm missing any ideas?
A few things to notice. You are sending the request as a JSON string (contentType: 'application/json' and JSON.stringify(o)) while on the server you are expecting an object of type MHolder. The default model binder won't do this transformation. You will need to either write a custom model binder capable of deserializing JSON back to an MHolder instance or send the request as key=value pairs (do not stringify):
var o = new Object();
o.message = 'Hi from the page';
$.ajax({
type: 'POST',
data: o,
dataType: 'json',
url: 'home/PingBack',
success: function (result) {
alert(result.success);
}
});
The code seems OK to me, at first glance.
try using...
data : {message : "Hi from the page."},
...to see if this causes the MHolder instance to be populated.
Also, use something like Fiddler to capture your requests and allow you to see exactly what is being posted.

Categories

Resources