parameters not being passed in to api controller from $http.post - c#

AngularJS:
$http.defaults.headers.post["Content-Type"]= "application/x-www-form-urlencoded";
$http({
url: 'http://localhost:17438/api/people/PostPerson/',
method: "POST",
data: { name: vm.parent[i].name, dob: '01/15/2001', email: vm.parent[i].email, phone: vm.parent[i].cell, carrierName: vm.parent[i].carrier, personTypeID: 1 }
})
.then(function (response) {
// success
alert('sucess : ' + response);
},
function (response) { // optional
// failed
alert('failure : ' + response);
});
I've also tried this variation:
var data = { name: vm.parent[i].name, dob: '01/15/2001', email: vm.parent[i].email, phone: vm.parent[i].cell, carrierName: vm.parent[i].carrier, personTypeID: 1 };
$http.post('http://localhost:17438/api/people/PostPerson/', data);
Parameters being passed:
{"name":"jv","dob":"01/15/2001","email":"j#live.com","phone":"5551212","carrierName":"Sprint","personTypeID":1}:
webAPI:
[HttpPost]
[HttpOptions]
public string PostPerson(newUserRegistration newReg)
{
var json = JsonConvert.SerializeObject(0);
person myPerson = new person();
myPerson.personName = newReg.name;
myPerson.personEmail = newReg.email;
myPerson.personPhone = newReg.phone;
myPerson.personPhoneCarrier = newReg.carrierName;
myPerson.personDOB = newReg.dob;
myPerson.familyID = newReg.familyID;
myPerson.personTypeID = newReg.personTypeID;
db.people.Add(myPerson);
db.SaveChanges();
return "got here";
}
public class newUserRegistration
{
public string name { get; set; }
public string email { get; set; }
public string phone { get; set; }
public string carrierName { get; set; }
public DateTime dob { get; set; }
public string registrationID { get; set; }
public int familyID { get; set; }
public int personTypeID { get; set; }
}
Parameter population:
I know it is hard to read but you can see the values I'm passing in are NOT being passed into my newUserRegistration object
I've looked at several questions on Stack that seems to reference this type of issue.
Angular POST to Web API doesn't pass data
issue in Angularjs $http.post to webapi
This project is currently using 1.3.15 - I'm not sure if upgrading to 1.5 help?
What am I missing on this?
UPDATE:
There was a comment that is now gone, but I stringified the data as suggested:
var data = JSON.stringify({ name: vm.parent[i].name, dob: '01/15/2001', email: vm.parent[i].email, phone: vm.parent[i].cell, carrierName: vm.parent[i].carrier, personTypeID: 1 });
$http.post('http://localhost:17438/api/people/PostPerson/', data);
I noticed something strange though. It is calling the API method 2 times, the 1st time has null data (as witnessed originally), but it calls it a 2nd time and the data is there!
I'm not sure why it is being called twice though? Is there anything I'm doing incorrectly now that I'm stringifying the data?
Update to double call:
I noticed the following:
You will notice one says OPTIONS and the other says POST. Now the webAPI also has the following tags:
[HttpPost]
[HttpOptions]
If I removed the Options, it fails (can't find 404). Do these tags have something to do with this?

Use JSON.stringify() to wrap your json
var url = 'http://localhost:17438/api/people/PostPerson/';
var data = JSON.stringify({ name: vm.parent[i].name, dob: '01/15/2001', email: vm.parent[i].email, phone: vm.parent[i].cell, carrierName: vm.parent[i].carrier, personTypeID: 1 });
$http.post(url, data);

As you're finding out, this is a web server issue more than an Angular one.
If your angular app is delivered on the same server:port as your service endpoints, try using a relative hyperlink and see if the OPTIONS request disappears. The presence of the domain name in a XmlHttpRequest for the application/json content-type is usually enough to trigger the CORS check.
I will say that I've seen this much more frequently when connecting to IIS, but it's not exclusive. A lot depends on the underlying server config. The OPTIONS request is like the handshake for SSL: the angular request is trying to figure out what the system will allow, then sending the payload once permissions are granted.
MDN - Access Control with CORS

Remove this:
$http.defaults.headers.post["Content-Type"]= "application/x-www-form-urlencoded";
You are telling the api server you are going to send it a form encoded body and you are instead sending it a JSON body and so when the api server goes to parse the body of the request it is null.
NOTE: If you are using Asp.Net Web Api's built in OAuth provider then you will need to post to the /token method using the application/x-www-form-urlencoded data type but for all other calls you can use JSON.
As for the duplicate requests that is caused by your browser making a CORS check. That is perfectly normal if your API hostname is different from you angular hostname.

Related

Trying to send FormData from Angular 5 app to ASP.NET 4.6.1 Web API : getting an "unsupported media type" error

So in my Angular front-end app I have a form and in the typescript file I create a new formdata object and append the items to it like so:
public postFormData() {
const form = $('#customListForm')[0];
const formData = new FormData();
formData.append('tenant', form[0].value);
formData.append('username', form[1].value);
formData.append('password', form[2].value);
formData.append('CL_title', form[3].value);
formData.append('CL_description', form[4].value);
formData.append('CL_contentType', form[5].value);
formData.append('CL_template', form[6].value);
this.http.post(this.apiURL, formData).catch(this.errorHandler).subscribe(res => this.formPosted(res));
// this.http.get(this.apiURL).catch(this.errorHandler).subscribe(res => this.formPosted(res));
}
In the end, my formData is filled in correctly. Now when I try to POST this to my ASP.NET 4.6.1 Web API, it gives me the following error:
POST http://localhost:52613/api/customlist 415 (Unsupported Media Type)
Here you can see my API code:
// POST api/customlist
[HttpPost]
public System.Web.Http.IHttpActionResult Post(CustomList data)
{
var test = HttpContext.Current.Request;
var testje = data;
return Ok("POST all good");
}
I assume the "CustomList data" is wrong? What I'd love is that the formData binds to my model, my model has the same fields as you can see here:
public class CustomList
{
public string Tenant { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public string CL_title { get; set; }
public string CL_description { get; set; }
public string CL_contentType { get; set; }
public string CL_template { get; set; }
}
In my headers I can see the following:
Response Headers: Content-Type: application/json
Request Headers: Content-Type: multipart/form-data
Could this be the issue?
Here's the weird part: I had previously created a .NET Core 2 Web API as well, and my post action looks like this (ignore the file stuff):
// POST api/input
[HttpPost]
public async Task<IActionResult> Post(SPInputObject data)
{
var uploads = Path.Combine(_hostingEnvironment.WebRootPath, "uploads");
string filePath = Path.Combine(uploads, data.File.FileName);
if (System.IO.File.Exists(filePath))
{
System.IO.File.Delete(filePath);
}
if (data.File.Length > 0)
{
using (var fileStream = new FileStream(filePath, FileMode.Create))
{
await data.File.CopyToAsync(fileStream);
}
}
ProvisioningService service = new ProvisioningService();
service.CreateSiteCollection(data.Tenant, data.Title, filePath);
return Ok("POST all good");
}
When I post my SAME Angular form/formdata to this api controller + action, it will enter the POST .... So why is it ok sending it to my .NET Core 2 Web API but not my ASP.NET 4.6.1 Web API?
Anyone know what could be the problem?
EDIT: trying to add content-type to my front-end Angular request doesn't work, here's what I tried:
private httpOptions = {
headers: new Headers({
'Content-Type': 'application/json'
})
};
Modifying my http post (i've added this.httpOptions):
this.http.post(this.apiURL, formData,
this.httpOptions).catch(this.errorHandler).subscribe(res =>
this.formPosted(res));
It then gives the following error on my this.httpOptions:
"message": "Argument of type '{ headers: Headers; }' is not assignable to parameter of type 'RequestOptionsArgs'.\n Types of property 'headers' are incompatible.\n Type 'Headers' is not assignable to type 'Headers'. Two different types with this name exist, but they are unrelated.\n Property 'keys' is missing in type 'Headers'."
You're posting FormData. Most browsers automatically set the Content-Type to "multipart/form-data" when you supply an instance of FormData. If you modify the code to use Content-Type "application/json" then you should also modify your request object to not use FormData, but JSON:
public postFormData() {
const form = $('#customListForm')[0];
const requestData = {
tenant: form[0].value,
username: form[1].value,
password: form[2].value,
CL_title: form[3].value,
CL_description: form[4].value,
CL_contentType, form[5].value,
CL_template: form[6].value
};
this.http.post(this.apiURL, requestData);
}
Try to setup the content type application/json and encoding to utf-8 on the angular side, or on the asp.net side, better on both. Usually it's caused by those two things. Asp.net core's model binding works slightly differently. Here's a good article about that
Model binding JSON POSTs in ASP.NET Core

Cannot post to another domain using ajax despite having CORS enabled

I'm using MVC.net and sending post data to my Web API 2 controller. I keep getting a 500 internal server error message.
I am trying to post to another domain if that matters? I have 2 visual studio instances running, one acting as the client, the other as the server. I have enabled CORS.
The GET works fine with this set up, but now I'm trying to post.
My controller on the 'server' is
[HttpPost]
[Route("api/cms/")]
public IHttpActionResult Post([FromBody]int accountId, [FromBody]string content, [FromBody]string paneId, [FromBody]string url)
{
//content
}
The javascript on the 'client' I'm using is
function ajaxStart(type, url, data, successDelegate, failDelegate, errorDelegate) {
$.ajax({
type: type.toUpperCase(),
url: url,
contentType: "application/json;charset=utf-8",
data: data,
dataType: "json",
success: function (response) {
successDelegate(response);
},
failure: function (e) {
failDelegate(e.statusText);
},
error: function (e) {
errorDelegate(e.statusText); //always hit
}
})
}
The data is created with (I've purposely used nonsense strings just to ensure there is nothing wrong with the formatting)
var data = JSON.stringify({ accountId: 1, paneId: "_selectedPaneNumber", url: "_url", content: "content" });
And the 'header' view in Google Chrome Dev Tools shows:
I have no idea what I've done wrong.
The javascript on the client side appears fine. The problem seems to be with the ApiController's action and parameter binding.
At most one parameter is allowed to read from the message body. So this will not work:
public IHttpActionResult Post([FromBody]int accountId, [FromBody]string content, [FromBody]string paneId, [FromBody]string url) { ... }
The reason for this rule is that the request body might be stored in a non-buffered stream that can only be read once.
Source: Parameter Binding in ASP.NET Web API : Using [FromBody]
Consider creating a model in the action server side
public class MyModel {
public int accountId { get; set; }
public string content { get; set; }
public string paneId { get; set; }
public string url { get; set; }
}
And update the action to expect that.
[HttpPost]
[Route("api/cms/")]
public IHttpActionResult Post([FromBody] MyModel model) {
//code removed for brevity
}
If you want to send a string as the body do the following:
Add the header: Content-Type: application/x-www-form-urlencoded
Change the string value in the body so it is prefixed with a = character: =5

Angular2/4 http POST services call .Net/MVC Web API 2.0 REST parameter is null

I have a .Net/C# Web API 2.0 REST service which works fine if test with Postman, but always get null parameter if call from Angular2/4 http service with Post.
below is the code:
C#:
public class UsersController : ApiController
{
// POST: api/users/login
public string login([FromBody]string value)
{
var ss = value;
return value;
}
}
Angular2 service:
login(email: string, password: string) {
const headers: Headers = new Headers();
headers.append('Content-Type', 'application/json');
const theBody = {'email': email, 'password': password};
const requestoptions: RequestOptions = new RequestOptions({
method: RequestMethod.Post,
url: this.host + '/users/login',
headers: headers,
body: JSON.stringify(theBody)
})
return this.http.request(new Request(requestoptions))
.map((res: Response) => {
return res.json;
})
.catch(this.logAndPassOn);
}
When test with Postman, I set header as Content-Type : application/json, and body select "raw".
everything looks the same, however the Angular2 Http Post service doesn't work anyway, I always get null value.
Thanks in advance for any any help.
Remove JSON.stringify: There's no need to convert it to a string.
On the Web Api side, you'll be better off with a POCO for the incoming data. Create a class that includes two string properties, e.g.:
public class LoginViewModel
{
public string Email { get; set; }
public string Password { get; set; }
}
Then, change [FromBody]string value to [FromBody]LoginViewModel viewModel.
To try and clarify a little more, there's a big difference between this:
{
"email": "some-email",
"password": "some-password"
}
and this:
"{ email: 'some-email', password: 'some-password' }"
The first example is a JSON object, whereas the second is just a string and nothing more. It doesn't matter that the data inside looks like JSON: it isn't. In your Postman example, you were actually sending a string, but perhaps Angular is being a bit clever and basically ignoring your JSON.stringify in the first place.

Post multiple objects to web API [duplicate]

This question already has an answer here:
Simple post to Web Api
(1 answer)
Closed 7 years ago.
I am trying to pass data to my web API using JSON objects. Sending a single object does seems to work fine but as soon as I put a second parameter, the second object does not even seems to initialize on the server side?
Please view the code below to see how I am handling the data parameter
[HttpPost("")]
public JsonResult Post([FromBody]Log_Header headerData,
[FromBody]Log_Detail detailData)
{
return Json("Test");
}
Each of the classes above have simple string data, eg of class below:
public class Log_Header
{
public int Id { get; set; }
public string Name{ get; set; }
}
Example of data being sent:
var header = {
Id: 0,
Name: "Test 3",
}
var detail = {
Id: 0,
Desc: "Test 1",
}
$http({
method: 'POST',
url: "api/addLog",
data : {
header: header,
detail: detail
}
})
This is all just demo data.
I have tried sending the data up in few different ways e.g below:
var data = {
Id: 0,
Name: "Test 3",
LogID: 0,
Desc: "Test",
}
But nothing seems to get this working, I'm guessing I am setting up the web API incorrectly?
Overall, the problem is [FromBody]Release_Log_Detail detailData does not receive any data at all and when viewing the object from a breakpoint it appears as null.
if anyone has any ideas please leave a comment or answer below. If you need anymore information from me please ask.
Whatever we post from angular $http, it consider a single object, so we need to read it in a single object on server
we can do like this
[HttpPost("")]
public JsonResult Post([FromBody]PostData data)
{
return Json("Test");
}
class PostData
{
public Log_Header LogHeader { get; set; }
public Log_Detail LogDetail { get; set; }
}
angular post
$http({
method: 'POST',
url: "api/addLog",
data : {
LogHeader : header,
LogDetail : detail
}
})
In the javascript
$http({
method: 'POST',
url: "api/addLog",
data : JSON.stringify({
header: header,
detail: detail
})
})
create a model
public class dataViewModel
{
public string[] header{ get; set; }
public string[] detail{ get; set; }
}
You have create a controller of name api and action name addLog
[HttpPost]
public JsonResult addLog(dataViewModel data)
{
return Json("Test");
}
hope this helps

Argument is null in call to .NET Web API GET method

I have two similar Web API controllers, one working and one not. Can't find why the broken one is not working. What happens is all the fields of the input argument are null. Here's the controller method signature:
public IEnumerable<Product> GetProducts([FromUri] StateQuery query)
Parameter type:
public class StateQuery
{
public State state;
public string username;
public string password;
}
Routing:
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "Default",
routeTemplate: "api/{controller}/{action}"
);
Calling the endpoint:
var uri = 'api/product/';
var query = {
username: $("#user").val(),
password: $("#password").val(),
state: { "name": $("#state").val(), "Counties": [{ "Name": $("#county").val() }] }
};
$.getJSON(uri + 'getProducts', query)
.done(function (data) {
$('#product').text(data);
console.log(data);
})
.fail(function (jqXHR, textStatus, err) {
$('#product').text('Error: ' + err);
});
Here's an example request:
http://localhost:47503/api/product/getProducts?username=auser&password=apassword&state%5Bname%5D=CO&state%5BCounties%5D%5B0%5D%5BName%5D=Boulder
I've tried attribute routing, tried calling from the browser address bar, tried simplifying the input to just username and password, no change. All the fields of query are always null. I also tried changing it to return a IHttpActionResult, which is the main difference between this and the working controller (other than what it does of course) but that had no effect. The method is getting called, so the routing is working, but there is something wrong with the argument binding that I'm just not seeing.
Does anybody see the problem or just a direction to look? I've spent all morning reading tutorials and SO questions and everything I'm seeing indicates that I'm on the right track. Maybe there's some little thing I'm missing because I've been staring at it too long.
Json.NET which ASP.NET Web API uses by default works on properties, not fields. You should convert them to using properties.
public class StateQuery
{
public State state { get; set; }
public string username { get; set; }
public string password { get; set; }
}

Categories