I am trying to get a json string from my angular app to a Web API. I have looked all over the internet the past 6 hours trying and failing miserably to figure out what I am doing wrong.
I have checked the network console and I can see the json as form data, but my WEB api for some reason is NOT getting it. I have looked at several other posts but none seem to help with my particular issue. Any direction would be great. I already tried using the "transform" fix, but that didn't help.
ENTRY POINTS TO WEB API
[HttpPost]
[Route("api/SkeltaInterfaceController/SaveWorkflow")]
public bool SaveWorkflow([FromBody] string json)
{
...
}
ANGULAR CALL
$scope.SaveWorkFlow = function () {
$http({
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
method: "POST",
url: webAPI,
data: {'DATA' : 'TEST DATA'
}
})
}
EDIT: I changed the angular call to this
$scope.SaveWorkFlow = function () {
$http({
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
method: "POST",
url: webAPI,
data: {'DATA' : 'TEST DATA'}
})
}
The Web API looks like this
[HttpPost]
[Route("api/SkeltaInterfaceController/SaveWorkflow")]
public bool SaveWorkflow([FromBody] TestModel json)
{
...
}
And the model
public class TestModel
{
public string DATA { get; set; }
}
I am still getting a null value for DATA though, something I setup wrong?
Though you have got an solution, there are some ways to POST simple string data (not an object) to a Web API service.
Let's say you have a POST API like this (in Test ApiController)
public void Post([FromBody]string value)
{
//do something with value
}
From AngularJS you can post to this method like
(1) data as JSON (default)
$scope.Test = function () {
$http({
method: "POST",
url: "/api/Test",
data: JSON.stringify("test")
});
};
This will use Content-Type: application/json by default. And server will treat the data as JSON. If you look at the request, you'll see the request body is a simple string, like
"test"
For complex objects, you'd see them JSON formatted.
(2) data as application/x-www-form-urlencoded (as in your example)
$scope.Test = function () {
$http({
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
method: "POST",
url: "/api/Test",
data: $.param({ "": "test" }),
});
};
Here, we are explicitly specifying the content type to be application/x-www-form-urlencoded, so we have to send data in that format (much like url query string). And, here, the empty key in data is just to satisfy Web API's strange model binding requirement! The resulting data will be encoded like
=test
which we'have done with $.param({ "": "test" }). One reason for this, FromBody is used mainly to send object, not simple primitive values.
So, the basic problem with your code was, you had specified Content Type : application/x-www-form-urlencoded and you were sending the data as JSON!
I think your issue comes down to the WebApi controller method expecting to receive a string, but you are passing it an object. Is it at least hitting the method but receiving null?
It depends what you are trying to send to the WebApi controller method, but if you mean to send an object, you should create a model that represents that object in your WebApi project and have the method take an object as the parameter.
For example, the way you have it right now you would do something like:
public class SaveModel
{
public string DATA {get; set;}
}
[HttpPost]
[Route("api/SkeltaInterfaceController/SaveWorkflow")]
public bool SaveWorkflow([FromBody] SaveModel model)
{ ...
Related
I'm migrating my code from .NET to .NET Core 6 and have hit a brick wall and googling doesn't seem to have helped so any advice, pointers will be welcome.
All of this works in .NET so it's clearly my understanding of how to migrate the API.
I am using a greasemonkey script to scrape some data and pass it to my site.
function sendHome() {
console.log(window.eval('window.PA_intel'));
GM.xmlHttpRequest({
method: "POST",
url: "https://localhost:7223/api/Parsing/Any",
data: "{ Data: '" + JSON.stringify(window.eval('window.PA_intel')) + "', Type: 'Intel'}",
headers: { "Content-Type": "application/json" },
onload: function (response) { console.log(response); toastr["success"]("Intel sent home!", "Phoenix"); },
onerror: function (reponse) {console.log("error: ", reponse)},
});
}
This grabs the data from a page an pushes it to an API route that is waiting on api/Parsing/Any
The debug and postman can trigger the API controller so I know the routing works but the body (Data and Type from the GM script) isn't coming with it.
I have a defined model to receive the data
public class ParseData
{
public string Data { get; set; }
public string Type { get; set; }
}
and my controller is set up to expect it, but in .NET CORE 6 it's just coming up null
[Route("api/Parsing/")]
public class ParsingAPIController : Controller
{
[Route("Any")]
public List<ParseResult> ParseAny(ParseData parseData)
//public List<ParseResult> ParseAny(string Data, string Type)
{
As I said the routing is being triggered but the parseData object is null and if I inpsect ParseAny to see what has been sent, I get an error with null body.
Any ideas where I am going wrong?
Fix ajax data
...
data: JSON.stringify({ Data: window.eval('window.PA_intel'), Type: 'Intel'}),
...
and an action header
[Route("Any")]
public List<ParseResult> ParseAny([FromBody]ParseData parseData)
You can try using the tag [FromBody] with the ParseData parameter.
Actually you need to do 2 things:
Add [ParseBody] to your parameter.
Add [HttpPost] as annotation to your method so that it accepts post requests and gets the post body in the request. Finally your code should be like below:
[Route("api/Parsing/")]
public class ParsingAPIController : Controller
{
[Route("Any")]
[HttpPost]
public List<ParseResult> ParseAny([FromBody]ParseData parseData)
{
I have two methods in my api controller with same name and same number of parameters but the type of one of the parameter is different. You can see here
[HttpGet]
public dynamic Add(String organizationId, Driving driving)
[HttpGet]
public dynamic Add(String organizationId, bool driving)
I am trying to call the api like this
var data {organizationId: "something", driving: true };
var ajaxConfig = {
url: some url,
type: "GET",
dataType: 'json',
crossDomain: true,
success: function (data) {
onDone();
callback(data);
},
error: function (error, textStatus, errorThrown) {
}
};
ajaxConfig.data = data;
$.ajax(ajaxConfig);
The system gets confused between which api to call. Am I doing it wrong? Is there some other way to do it?
You could use attribute routing to make the methods point to different routes in the controller
[HttpGet]
[Route("api/controller/add1")] // Url http://url.domain.com/api/controller/add1
public dynamic Add(String organizationId, Driving driving)
[HttpGet]
[Route("api/controller/add2")] // Url http://url.domain.com/api/controller/add2
public dynamic Add(String organizationId, bool driving)
The controller can only make the difference between two identically named methods in two ways:
Via HttpVerb attributes: In this case you could apply [HttpGet] to the first method and [HttpPost] to the second. When calling from a client you must use the Get method when using the first one and the Post method when using the second one.
Via Route attribute: In this case you tell MVC what route to take for each method (ex: [Route("api/mycontroller/AddWithBoolean")] ). In this case the client chooses the correct method by using the correct route.
In case you dont want to make the distinction in the client and you want your server to do the distinction you need another approach.
You can create a method like this:
[HttpGet]
public dynamic Add(String organizationId, object driving)
{
if (driving is Driving)
// execute code
else
// execute other code
}
This example is far from complete but it could be an approach.
With regards,
John
So essentially, I'm building a web API, and I'm trying to use ajax to query a web service that accepts two arguments. I need to pass a List of Stings (SSNs) and I need to pass a single string to determine which environment it queries. ("a" for acceptance, and "i" for integration).
I'm using cshtml with razor. And so far this section is successfully giving me what I want from the divs.
var pInputSssns = document.GetElementById(“SSNinput”).value;
var pTestRegion = document.GetElementById(“testRegion’).value;
However, just beneath it. I'm trying to insert both these params into an ajax call.
$.ajax({
type: 'GET',
contentType: "application/json; charset=utf-8"
url: "myurl",
data:"{}",
success: function (data) {
// populate a table
}
});
I've heard multiple opinions on how that can be done. Can I serialize them both as JSON, and then put two JSON objects in the data parameter? I've also heard that I can pass a c-sharp object, but if I try and do that I can't access the html variable while I'm inside the Razor code.
#{ AjaxParam ap = new AjaxParam(); ap.pInputSsns = pInputSsns;}
Is there a good way to pass both of them in there? For reference, here's the Controller:
[ScriptMethod (ResponseFormat = Response Format.Json)]
[System.Web.Http.HttpGet]
public JArray GetSSNAssociations([FromUri] List <string> pInputSsns, string pTestRegion)
{
\\ do something
}
Appreciate it everyone.
First, create a DTO class for the data you want to send.
public class SearchRequest
{
public List<string> SsnList { set; get; }
public string Environment { set; get; }
}
Now in your WebApi controller's Post method will have this class as the parameter so that when the client sends a request, the default model binder will be able to map the request values to the properties of an object of this class.
public class ProductsController : ApiController
{
public HttpResponseMessage Post([FromBody]SearchRequest req)
{
// I am simply returning the same object back. But you can do whatever you want
// Check req.SsnList and req.Environment properties and do something useful.
return Request.CreateResponse(HttpStatusCode.OK, req);
}
}
Now from the client side code, You can build a javascript object which resemebles the structure of our DTO class and send it using jQuery ajax.
var model = { Environment: "I", SssList: ["375329567", "3583345"] };
var url="../api/products";
$.ajax({
type: "POST",
data: JSON.stringify(model),
url: url,
contentType: "application/json"
}).done(function (res) {
console.log('res', res);
// Do something with the result :)
});
Here is a post explaining the different options to send client side data to web api in detail.
I hardcoded the value of url variable. You should consider using the Html helper methods like Url.Action to generate the correct relative path to your app endpoint as explained in this post.
Here is my ajax that is being invoked as a function when an array has data.
function sendDataToController() {
$.ajax({
type: 'POST',
url: '/Home/Results',
cache: false,
traditional: true,
contentType: "application/json",
data: { FormData : exampleFormData },
success: function (data) {
alert("sent data to controller")
},
error: function (data) {
alert("Error " + data.responseText);
}
});
}
The array looks like this:
var exampleFormData = [];
And the JSON looks like this currently with some more data but shortened for display purposes.
"[{\"Birthdate\":\"1947-03-21\",\"ROWID\":\"000001\",\"SpecCodes\":\"987654\"}]"
This JSON is being pushed into the array multiple times before using ajax to send to the controller.
exampleFormData.push(jsonData);
The control that this is being passed into looks like this:
public ActionResult Results(string exampleFormData)
{
var formDataList = JsonConvert.DeserializeObject<List<SampleFormData>>(exampleFormData);
return View();
}
And here is the class that models that "SampleFormData" list
public class SampleFormData
{
public string Birthdate { get; set; }
public string ROWID { get; set; }
public string Score { get; set; }
public string SpecCodes { get; set; }
}
As is, this produces a 500 internal server error. Can anyone provide any input on what is being done incorrectly here?
Edit: The solution for this was to remove the contentType line from ajax completely and was provided by Rion in the responses.
There are a few things to consider with the code you provided that could be causing your issue.
Ensuring You Can Post Properly
In order for your Controller to actually acknowledge the jQuery call, you'll need to ensure that the Controller Action is decorated with the [HttpPost] attribute, indicating it should be used for POST calls :
[HttpPost]
public ActionResult ExamineeResults(string exampleFormData)
{
// Your code here
}
Ensuring You Are Targeting The Proper Action
Your AJAX call currently is targeting Home/Results, however the name of your actual Controller Action is ExamineeResults. Unless you have some specific routing rules in place, you should use the existing name to make sure you target it correctly :
url: '/Home/ExamineeResults',
Additionally, if you have this within your View, you can use the Url.Action() method to resolve the proper location :
url: '#Url.Action("ExamineeResults","Home")'
Using Proper Parameters
MVC will only know how to properly map data as you specify it. Currently you are posting your contents as such :
data: { FormData : exampleFormData },
This means that the name of your parameter in your Controller Action should match that exactly (i.e. FormData instead of exampleFormData) :
public ActionResult ExamineeResults(string FormData)
Putting All Of These Together
You should be able to resolve this by updating your code as follows :
$.ajax({
type: 'POST',
// Use Url.Action() to resolve the proper URL
url: '#Url.Action("ExamineeResults","Home")',
cache: false,
// Use JSON.parse() to serialize your content to send accross
data: { formData: JSON.parse(exampleFormData) },
success: function (data) {
alert("sent data to controller")
},
error: function (data) {
alert("Error " + data.responseText);
}
});
along with the following Controller Action :
[HttpPost]
// You can let MVC perform the binding for your by mapping your content
// to an array of your SampleFormData objects
public ActionResult ExamineeResults(SampleFormData[] formData)
{
// Do your thing here (as formData is already serialized)
return View();
}
You can see an example of this here and demonstrated below :
One of the issue with this call could be the fact that you're returning a View to an ajax call. As far as I know, this is not possible. If you must post to this ActionResult you must do a post. Also, make sure your routing is correct. Running this code as is will not reach the desired endpoint as your ActionResult is named "ExamineeResults" and your url is "/Home/Results". Hope this helped.
I am running into a problem where I can't seem to pass this data properly from jquery to the web api.
Here is my javascript code:
var chartRequestParams = [
{ QueueMode: "Investigations", DataMode: "items_completed" },
{ QueueMode: "Investigations", DataMode: "items_completed_avg_age" },
{ QueueMode: "Investigations", DataMode: "active_items" }
];
$.post('/api/dashboard/GetActiveAgeChart', chartRequestParams, function (data) { });
Here is my Web API Code:
[HttpPost]
public List<HighChartsResponse> GetActiveAgeChart(List<ChartRequestParam> chartRequestParams)
{ .....continued....
It's not even making it into the above method
Here is my "model"
public class ChartRequestParam
{
public ChartRequestParam()
{
this.QueueMode = string.Empty;
this.DataMode = string.Empty;
}
public string QueueMode { get; set; }
public string DataMode { get; set; }
}
I've tried soooo many variations of this code with no success. Basically I'm just trying to post a List to the web API method.
I receive a 500 server error, and it if i set a breakpoint inside the "GetActiveAgeChart" method it doesn't even hit it.
First, I assume your controller is named DashboardController. If so, you will need to post to /api/dashboard without the action method in the URI. Web API does support RPC-style but it is not probably important for this.
Second, you will need to stringify the payload, something like this.
$.ajax({
url: '/api/dashboard', type: 'POST', contentType: 'application/json',
data: JSON.stringify(chartRequestParams)
});
This will post the request message as JSON. If you prefer it to be www-form-urlencoded, you will need to read http://aspnetwebstack.codeplex.com/workitem/177.