I am having issues in Asp.Net Core with trying to pass data in the Ajax call into the parameter of the API Controller function.
I am using the data field in the Ajax call to pass the value of "id". In the API controller this value should be assigned to the "id" parameter, but never is.
// Ajax call
$.ajax({
url: "/api/apicomment/GetPostComments",
type: "GET",
data: { 'id' : 2 },
dataType: "json",
}).done(function (data) {
// Some function
}).fail(function (handleError) {
// Some function
});
The API controller is a normal scaffolded API Controller where I get specific comments with the id parameter. But every time I make a call I get the value 0.
// API Controller
[HttpGet("{id}")]
[Route("GetPostComments")]
public async Task<ActionResult<IEnumerable<Comment>>> GetSpecificComment(int id)
{
var comment = await _context.Comment.Where(c => c.PostId == id).ToListAsync();
if (comment == null)
{
return NotFound();
}
return comment;
}
Have tried many different things, but I can't quite figure it out.
Would love any feedback that might help!
You can also pass via query string :
Comment out data line :
// Ajax call
$.ajax({
url: "/api/apicomment/GetPostComments",
type: "GET",
data: { 'id' : 2 },
}).done(function (data) {
// Some function
}).fail(function (handleError) {
// Some function
});
use FromQuery to get parameter :
public async Task<ActionResult<IEnumerable<Comment>>> GetSpecificComment([FromQuery]int id)
Few thing to try
First about your API url it should be like this
url: "/api/GetPostComments"
It would be much cleaner
Second your data should be like this
data: { id : 2 }
Finally you cant mix up between these 2
[HttpGet("{id}")]
[Route("GetPostComments")]
It should be like this
[Route("api/[controller]")]
[ApiController]
public class SomeController : ControllerBase {
[HttpGet("GetPostComments/{id}")]
public async Task<ActionResult<IEnumerable<Comment>>> GetSpecificComment(int id)
{
var comment = await _context.Comment.Where(c => c.PostId == id).ToListAsync();
if (comment == null)
{
return NotFound();
}
return comment;
}
}
So your url should be something like this api/your-controller/GetPostComments/1
You can read more here
Related
Have followed a number of tutorials on the net but still getting the same result. Microsofts documentation is so in-depth considering all I want to is in essence send one variable to a controller.
My client side code looks like this:
var obj = { send: 'test' };
$.ajax({
url: '/Countries/GetVotes',
type: 'POST',
contentType: "application/json",
data: JSON.stringify(obj),
success: function (data) {
if (data === null) {
// TODO
} else {
console.log(data);
}
},
error: function (error) {
console.log(error);
}
});
Then the controller would look like this:
[HttpPost]
public async Task<JsonResult> GetVotes(string send)
{
try
{
var votes = ctx.Candidates.Where(x => x.Country == send)
.OrderByDescending(x => x.Votes)
.ToList();
return Json(votes);
}
catch (Exception ex)
{
logger.Error(ex);
}
return Json("foo");
}
All standard and used to work in .NET framework 4.7.2, anyone whose done any MVC would be very familiar with this approach.
I've made the decision to try using .net core 3.1. Am hitting all the right breakpoints, the problem I have is the string called "send" is sent to my controller as null.
Anybody know the simplest way to get this working?
What you're passing in is a JSON object
{ send: "test" }
What you're expecting in the request body in the controller is just a string. You could try creating a request object that represents the data structure you're expecting:
public class Request {
public string send { get; set; }
}
Then you can update your controller method to
public async Task<JsonResult> GetVotes([FromBody]Request request)
And further access the send property through request.send.
you don't neeed stringify when you are sending string already. And remove content type too. Default would be ok.
So try this
$.ajax({
url: '/Countries/GetVotes',
type: 'POST',
data: obj,
success: function (data) {
if (data === null) {
// TODO
} else {
console.log(data);
}
},
error: function (error) {
console.log(error);
}
});
I have a simple action method that taking 2 parameter but when I call it by using jQuery Ajax in the Chrome Developer tool and Network tab > Xhr > Request status Code : 500 Internal Server error....
I am trying to find out the actual error but I can't get it?
NOTE: when I throw a breakpoint at the actionMethod & when I click on a button the ajax call is issuing but during I can't get control and the breakpoint, so this means that the ajax call isn't reaching the action method as well.
ActionMethod:
[HttpPost]
public ActionResult LikePost(int userId, int entryId)
{
return Content("User Id Is : " + userId + "Post Id is : " + entryId);
}
jQuery:
jQuery.ajax({
url: "#Url.Action("LikePost", "Home")",
method: "POST",
data: {
"userId": CurrentButton.attr("data-UserId"),
"entryId": CurrentButton.attr("data-entryId")
},
success: function () {
console.log("Succeded");
},
error: function () {
console.log("Failed.");
}
});
I am stuck for the last 2+ hours... The actual scenario is little different in my project but the problem I am facing is exactly this one.
You use method POST then you need use only one variable on your server side action.
You can create a class like it:
public class User
{
public int UserId { get; set; }
public int EntryId { get; set; }
}
After you need to change you MVC action:
[HttpPost]
public ActionResult LikePost(User user)
{
return Content("User Id Is : " + user.userId + "Post Id is : " + user.entryId);
}
And send this data as JSON:
var data = {
userId: CurrentButton.attr("data-UserId"),
entryId: CurrentButton.attr("data-entryId")
};
jQuery.ajax({
url: "#Url.Action("LikePost", "Home")",
method: "POST",
data: JSON.stringify(data),
success: function () {
console.log("Succeded");
},
error: function () {
console.log("Failed.");
}
});
When you submit data to the controller using Ajax, you can either use HttpPut or HttpPost annotations only.
In both cases, at controller side you should use DTO (Data Transfer Object) as parameter. So make a class (DTO Class) and your error will be gone.
I post data using fetch like this in my client js scripts
fetch('/myarea/mycontroller/myaction', {
method: 'post',
body: JSON.stringify({ name: namevalue, address: addressvalue })
})
.then(function (response) {
if (response.status !== 200) {
console.log('fetch returned not ok' + response.status);
}
response.json().then(function (data) {
console.log('fetch returned ok');
console.log(data);
});
})
.catch(function (err) {
console.log(`error: ${err}`);
});
}, false);
Then on my controller
[HttpPost]
public async Task<IActionResult> MyAction(string name, string address)
{
// Error, name and address is null here, shouldn't be!
// more code here ...
}
My controller action is being called correctly, and I am able to debug inside it, but no data being passed. What could be wrong here? Thanks
The controller action is expecting query parameters (/myaction?name=myname&address=myaddress). That's the default.
You're sending them in the body.
You can change the javascript to send them as query parameters. (see here: https://github.com/github/fetch/issues/256)
Or you can tell the controller action to take the values from the body:
[HttpPost]
public async Task<IActionResult> MyAction([FromBody] Person person)
{
var myName = person.Name;
}
public class Person
{
public string Name {get; set; }
public string Address {get; set; }
}
The [FromBody] attribute kicked in for me only after I defined the header that it is an "application/json" type:
fetch('api/Profile/Update', {
method: 'post',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ description: "Some text here" })
});
And this is how the controller action looks like:
[HttpPost("[action]")]
public async Task<IActionResult> Update([FromBody] ProfileUpdateModel profileUpdateModel)
{
//Do some stuff here...
return RedirectToAction("/", "HomeController");
}
And the description property now receives the value from the request. Hope this gives final clarity to somebody tackling with the issue.
Or if you had <form>...</form> you could use
fetch('/url', {
method: 'POST',
credentials: 'include',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: $('#editContactModal form').serialize()
// body like "id=1&clientid=3&name=me&phones=123&email=#mail.com"
})
without [FromBody] !!! (just with regular action method in controller)
I have a class in my web project:
public class MyClass
{
public int? Param1 { get; set; }
public int? Param2 { get; set; }
}
which is a parameter in my controller method:
public ActionResult TheControllerMethod(MyClass myParam)
{
//etc.
}
If I call the method using POST, the model binding works automatically (I use angular on the js side, which likely doesn't matter):
$http({
method: "post",
url: controllerRoot + "TheControllerMethod",
data: {
myParam: myParam
}
}).success(function (data) {
callback(data);
}).error(function () {
alert("Error getting my stuff.");
});
If I use a GET, the parameter is always null in the controller.
$http({
method: "get",
url: controllerRoot + "TheControllerMethod",
params: {
myParam: myParam
}
}).success(function (data) {
callback(data);
}).error(function () {
alert("Error getting my stuff.");
});
Does complex model binding using the default model binder only work for POSTs, or is there something I can do to make this work with a GET?
The answer is Yes. The difference between GET and POST requests is that a POST body can have a content type so they can be interpreted correctly on the server side as XML, or Json, so on; for GET, all you have is just a querystring.
With ASP.NET MVC you can indeed bind your model on a GET request, as long as you have the same query string parameter names as of the property names of your Model class. Example from this answer:
public class ViewModel
{
public string Name { set;get;}
public string Loc{ set;get;}
}
You can do a Get request like this
MyAction?Name=jon&Loc=America
and MVC will automatically bind your model:
[HttpGet]
public ViewResult MyAction(ViewModel model)
{
// Do stuff
return View("ViewName", model);
}
Why are you calling the property "data" in the POST, and "params" in the GET? Both should be called "data".
$http({
method: "get",
url: controllerRoot + "TheControllerMethod",
data: {
myParam: myParam
}
}).success(function (data) {
callback(data);
}).error(function () {
alert("Error getting my stuff.");
});
I've got some api controller with this action:
public class ProxyController : ApiController {
public async Task<HttpResponseMessage> PostActionAsync(string confirmKey)
{
return await Task<HttpResponseMessage>.Factory.StartNew( () =>
{
var result = GetSomeResult(confirmKey);
return Request.CreateResponse(HttpStatusCode.Created, result);
});
}
}
And here is my api routing confuguration:
routes.MapHttpRoute("DefaultApi", "api/{controller}/{action}/{id}", new { id = RouteParameter.Optional });
When I try to make any Post/Get Requests to this action, it's returns '404' error. How can I fix it? All other not-async actions in this controller works fine.
UPD. JS query:
$.ajax({
url: Url + '/api/Proxy/PostActionAsync',
type: 'POST',
data: { confirmKey: that.confirmKey },
dataType: 'json',
xhrFields: { withCredentials: true },
success: function (data) {
............
},
error: function (jqXHR, textStatus, errorThrown) {
............
}
});
UPD. Resolved by adding [FromBody] to my parameters in action method just like in J. Steen's answer, now it's look's like
public class ProxyController : ApiController {
public async Task<HttpResponseMessage> PostActionAsync([FromBody]string confirmKey)
{
var someModel = new SomeResultModel(User.Identity.Name);
await Task.Factory.StartNew(() => someModel.PrepareModel(confirmKey));
return Request.CreateResponse(HttpStatusCode.OK, someModel);
}
}
And it works!
The routing configuration for Web API works a little differently than MVC.
Try
routes.MapHttpRoute("DefaultApi", "api/{controller}/{id}", new { id = RouteParameter.Optional });
Note the missing {action} as that is resolved by Web API at call-time, automagically, depending on the HTTP verb you use for your request.
Consider this article on Web API routing which lists (as an example):
HTTP Method URI Path Action Parameter
GET api/products GetAllProducts (none)
GET api/products/4 GetProductById 4
DELETE api/products/4 DeleteProduct 4
In your case, the async version of an action is also resolved automatically.
POST api/products PostActionAsync (Post data)
Since we now know the controller name, requests would be like:
GET api/proxy
GET api/proxy/4
POST api/proxy (with post data)
Edit:
After additional research (brief, I admit) I have found the issue.
You need to add [FromBody] infront of your in-parameter.
public async Task<HttpResponseMessage> PostActionAsync([FromBody] string confirmKey)
This, combined with sending just the value (no wrapping json) works wonders. Set content type to "application/x-www-form-urlencoded" instead of json, and send your parameter as "=" + that.confirmKey.
Alternative:
If you don't want to fiddle around with content-types and prefixing =-signs, just send it as part of the querystring. Forget the [FromBody] and the rest. Call
/api/Proxy/PostActionAsync?confirmKey=' + that.confirmKey
Additional, exhaustive information in this blog.
Is that change possible?
public async Task<HttpResponseMessage> PostActionAsync()
{
var result = await GetSomeResult();
return Request.CreateResponse(HttpStatusCode.Created, result);
}