I have seen similar case to mine answered but I have specific need that always differed from others problem.
I am sending json data from my html page to the MVC Web API. Unfortunately the data I am receiving is ALWAYS null (I have tried a lot of different things here). The thing is I really need to received the data as json (string), because my data is very complex and cannot be simply deserialized by the Web API (I have my own custom deserializer that does it).
Heres the code!
First, the web api controller that will receive the ajax post request
public class ActivityController : ApiController
{
// POST api/activity
public string Post([FromBody]string json)
{
}
}
Then, the ajax request itself
$.ajax("/api/activity", {
contentType: "application/json",
data: { json: ko.mapping.toJSON(fusionedModel) },
type: "POST",
success: function (result) {
...
}
});
As far as the data is concerned, it is rendered well (I've used that same request with MVC (not Web Api) and the server was receiving the string perfectly... now for some reason, in my web api controller, the "json" param is ALWAYS null. As I said before, it is IMPORTANT that I receive the data as a json string.
EDIT : I found that my question is a duplicate of this one : POST JSON with MVC 4 API Controller
But I really don't like the answer... having to create an object just to encapsulate the string is very dirty...
I recommend you avoid using standard body parameter binding as that mechanism assumes that you are trying to deserialize the body into a CLR object. Try this,
public class ActivityController : ApiController
{
// POST api/activity
public async Task<HttpResponseMessage> Post(HttpRequestMessage request)
{
var jsonString = await request.Content.ReadAsStringAsync();
return new HttpResponseMessage();
}
}
If you really want to use parameter binding, you can do this.
public HttpResponseMessage Post(JToken jToken)
{
return new HttpResponseMessage()
{
Content = new StringContent(jToken.ToString())
};
}
Please try to use the [HttpPost] Attribute that can be located on System.Web.Http;
public class ActivityController : ApiController
{
// POST api/activity
[HttpPost]
public string Post([FromBody]string json)
{
}
}
I could be wrong here, but it looks like you haven't included your action in the post URL. Try changing
$.ajax("/api/activity", {
contentType: "application/json",
data: { json: ko.mapping.toJSON(fusionedModel) },
type: "POST",
success: function (result) {
...
}
});
To
$.ajax("/api/activity/POST", {
contentType: "application/json",
data: { json: ko.mapping.toJSON(fusionedModel) },
type: "POST",
success: function (result) {
...
}
});
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 the following JQuery code in my .cshtml file.
$.ajax({
type: "POST",
url: urlPath,
dataType: 'json',
contentType: 'application/json',
data: JSON.stringify({ pendingList: pendingList })
}).error(function (err) {
alert("Error " + err.status);
});
The pendingList object populates with correct values.I could see the values in the post request.
Request Data View
My ASP.NET Controller
[HttpPost]
public ActionResult CreateMultiRequest(List[] pendingList)
{
But I see null for the pendingList.Any help appreciated.
You're posting JSON that looks like:
"pendingList": {
//...
}
Thus, .Net is trying to bind the posted data to an object shaped like:
class SomeType
{
public List[] SomeOtherType { get; set; }
}
Instead, just call JSON.stringify(pendingList) which will send:
{
//...
}
You don't need to send a named object to the ASP .Net controller. It already expects the format of the object to match the type of parameter in the controller method.
There are two ways to fix this.
One:
Just like suggested in other answers use a generic list of type
[HttpPost]
public ActionResult CreateMultiRequest(List<PnedingList> pendingList)
Two:
Use FromBody attribute to help the runtime to retrieve the object from request body
[HttpPost]
public ActionResult CreateMultiRequest([FromBody]List[] pendingList)
I tried to pass more than one parameter from client-side using jQuery to ASP Web API method, but the method can't accept that. I tried some of the solutions but the same thing.
Web API:
[HttpPost]
[ResponseType(typeof(Message))]
[Route("api/Messages/send-message")]
public async Task<IHttpActionResult> SendMessage(Email email, Message message){}
jQuery:
$.ajax({
url: '/api/Messages/send-message',
method: 'POST',
contentType: "application/json; charset=utf-8",
dataType: "json",
data: JSON.stringify({
email: EmailsArray,
title: $('#txtTitle').val(),
body: $('#txtContent').val(),
}),
success: function (response) {
console.log(response);
});
Error Message:
"message":"An error has occurred.","exceptionMessage":"Can't bind multiple parameters ('email' and 'message') to the request's content.","exceptionType":"System.InvalidOperationException"
If you're sending the data as JSON then all the data needs to be contained in a single coherent JSON structure. Having two separate input parameters on the server side does not fit with this concept.
In this situation you can create a DTO (Data Transfer Object) which is a class holding all of the items you want to transfer. Something like this:
public class EmailMessageDTO
{
public Email email { get; set; }
public Message message { get; set; }
}
Then you define the action method as accepting this single over-arching object
public async Task<IHttpActionResult> SendMessage(EmailMessageDTO dto) { }
And in the JavaScript:
data: JSON.stringify({
email: EmailsArray,
message: {
"title": $('#txtTitle').val(),
"body": $('#txtContent').val(),
}
}),
It's quite similar to the concept of having a ViewModel in MVC.
You need to add [FromBody] attribute to parameter and you need to make post data to application/x-www-form-urlencoded and you send only email parameter, you need to add message parameter if you wanna send title and body you need to create model like
model:
public class EmailSendModel(){
public string email{get;set;}
public string title{get;set;}
public string body{get;set;}
}
controller:
[HttpPost]
[ResponseType(typeof(Message))]
[Route("api/Messages/send-message")]
public async Task<IHttpActionResult> SendMessage([FromBody]EmailSendModel model){}
I am developing an Azure Web app with a database. I've a model and controller for the database. I'm trying to Post data on the database, but have some trouble understanding why does this code send a 404 error when sending data from the Web-Client to the controller.
Here is how I send the data in AngularJS (parameter is a Json string):
$http({
method: 'post',
url: serviceBasePath + "/api/suscribe",
data: parameter,
headers: { 'Content-Type': 'application/json' }
}).then(function (response) {
userService.SetCurrentUser(response.data);
defer.resolve(response.data);
}, function (error) {
defer.reject(error.data);
})
On the controller side, I get 404 if the controller is :
[HttpPost]
[Route("api/suscribe")]
public IHttpActionResult PostGTW_Utilisateur(String JsonString)
{
//
}
But if I leave the model as a parameter, the 404 error is gone :
[HttpPost]
[Route("api/suscribe")]
public IHttpActionResult PostGTW_Utilisateur(User u)
{
//
}
Json object class :
public class JsonSuscribeModel
{
public Utilisateur user { get; set; }
public string guid { get; set; }
public string password2 { get; set; }
}
You miss the endpoint since it does not know what JsonString is. You sent a JSON but in the controller model, you told it to listen for string. Open up Chrome (or other) dev tools and see EXACTLY what you are sending with the request.
Here is another tip:
$http({
method: 'post',
url: serviceBasePath + "/api/suscribe",
data: parameter,
headers: { 'Content-Type': 'application/json' }
}).then(function (response) {
userService.SetCurrentUser(response.data);
defer.resolve(response.data);
}, function (error) {
defer.reject(error.data);
})
I have seen the misuse of promises SO many times. Why would you use $http (which is itself a promise) and then process it in service and return ANOTHER promise? You can simply return $http (and resolve its promises in a controller. You are gonna have to resolve this new promises you are returning anyway, so why have an extra step.
return $http({
method: 'post',
url: serviceBasePath + "/api/suscribe",
data: parameter,
headers: { 'Content-Type': 'application/json' }
}).then(function (response) {
userService.SetCurrentUser(response.data);
return response.data;
}, function (error) {
return error.data;
})
This way you return entire $http and you instruct it what to return in success and error. Since itself it's a promise it will behave same as before.
Thanks for the tips.
The solution was to use the JsonModel I had as a parameter :
public IHttpActionResult PostGTW_Utilisateur(JsonSuscribeModel JsonModel)
I'm developing an application using asp.net, mvc6 and angularjs on my angular service. When I make a request to an action method, I get no passed data.
When I have checked the request, I could see an exception that caused by:
Form '((Microsoft.AspNet.Http.Internal.DefaultHttpRequest)this.Request).Form'
threw an exception of type
'System.InvalidOperationException' Microsoft.AspNet.Http.IFormCollection
{System.InvalidOperationException}
exception message saying "Incorrect Content-Type:application/json;charset=UTF-8"
my angular service
return $http({ method: 'POST', url: 'home/createEvent', eventDetails: event })
.success(function(data, status, headers, config) {
return data;
})
.catch(function(data, status, headers, config) {
console.log(data);
});
on my controller
[HttpPost]
public IActionResult CreateEvent([FromBody]Event eventDetails)
{
return Json(new {dsd=""},
new JsonSerializerSettings {ContractResolver = new CamelCasePropertyNamesContractResolver()});
}
The accepted answer didn't work for me. For me, the solution was to add a header to the $http call:
$http({
url: "/install",
method: "POST",
data: data,
headers: {
"Content-Type": "application/x-www-form-urlencoded"
}
})
.success(...);
Hope the following examples helps you.
Try to decorate your controller with
[Produces("application/json")]
[Route("api/[controller]")]
Since you din't show your controller name I will give you a fictitious full working example
controller
[Produces("application/json")]
[Route("api/[controller]")]
public class DashBoardLayoutApi : Controller
{
public DashBoardLayoutApi()
{ }
[HttpPost]
public void Post([FromBody] LoginViewModel data)
{ }
}
C# viewmodel
public class LoginViewModel
{
public string Email { get; set; }
public string Password { get; set; }
}
HTML/JS
<script>
var data = {
Email: 'Test',
Password: 'Test',
RememberMe: true
};
$("#test").click(function() {
$.ajax({
url: '/api/DashBoardLayoutApi',
type: 'POST',
dataType: "json",
contentType: "application/json; charset=utf-8",
data: JSON.stringify(data),
});
}
</script>
<button id="test"> Save Layout</button>
Results
In my case, adding [Produces("application/json")] did nothing, but adding the [FromBody] attribute to the parameter is what did the trick!
The hidden's answer is great. However, I still had empty model in C# controller, even after I implemented hidden's approach in my application. After digging around a bit I found that the issue was in incorrect client model created in JS code, which cannot be deserialized on the server (null can not be converted to type Guid).
For some reason, model binder does not throw exceptions in such cases:
https://learn.microsoft.com/en-us/aspnet/core/mvc/models/model-binding
When a parameter is bound, model binding stops looking for values with that name and it moves on to bind the next parameter. If binding fails, MVC does not throw an error. You can query for model state errors by checking the ModelState.IsValid property.
So, check the ModelState.IsValid property in C# controller to make sure you passed valid model and maybe consider using custom model binder to catch model binding errors and log them.