I have the following post method in my WEB API controller:
public async Task<HttpResponseMessage> SendPost(Application application)
I call it through javascript using angular.js $http.post and pass through the application parameter as JSON:
$http.post("/api/AController/SendPost", JSON.stringify(application)).
success(function (data, status, headers, config) {
}
This works.
Now I want to pass through a second parameter as a simple string (I can't modify the existing application JSON object).I tried a few different ways suggested on the web but none of them seem to work. I need to be able to do soemthing like this:
Controller:
public async Task<HttpResponseMessage> SendPost(RentalApplication application,string test)
Javascript:
$http.post("/api/TessIntegration/SendPost", {application:JSON.stringify(application),test:"Some value"}).
success(function (data, status, headers, config) {
}
You cannot get multiple objects from the body in WebAPI.
If you were passing two complex objects, the solution would be to wrap them into another complex object.
public async Task<HttpResponseMessage> SendPost(SuperComplex request)
public class SuperComplex {
public Application Application { get; set; }
public AnotherObject Object { get; set; }
}
$http.post("/api/AController/SendPost", { application: application, Object: {} });
Now if the 2nd parameters is a simple object (such as a string) you can just pass it by queryString instead.
$http.post("/api/AController/SendPost?test=some+value", application );
Also, you don't have to stringify, Angular does it for you.
Found a solution using Newtonsoft.Json.Linq.JObject:
Controller:
public async Task<HttpResponseMessage> SendPost(JObject data)
{
RentalApplication application = data["application"].ToObject<RentalApplication>();
string test = data["test"].ToObject<string>();
}
Javascript:
var data = {
application : application,
test : "sample value"
};
$http.post("/api/TessIntegration/SendPost",data).
success(function (data, status, headers, config) {
}
Update to #Denys answer. Use of JObject is not necessary. Simply use JSON.stringify(data) in your javascript as:
JAVASCRIPT:
var data = {
application : application,
test : "sample value"
};
$http.post("/api/TessIntegration/SendPost",data).
success(function (JSON.stringify(data), status, headers, config) {
C#
Change definition of controller endpoint as:
public async Task<HttpResponseMessage> SendPost(RentalApplication application, string test)
{
RentalApplication application = data["application"].ToObject<RentalApplication>();
string test = data["test"].ToObject<string>();
}
Related
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
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.
I've been trying to figure this out for hours now but none of the solutions seem to help. I have an MVC6 project with AngularJs. I am able to connect, so my routes are working, and I am able to get data back if I hard code a string or something, but I can't seem to access the data sent to the server.
My angularjs http request code:
var app = angular.module('APIService', []);
app.factory('APIService', function ($http) {
var api = {};
api.getBuyer = function (data) {
return $http.post('/api/buyer', data);
}
return api;
});
The angularjs function call
APIService.getBuyer({ Url: 'samirbashir5739', FirstName: 'Samir' }).success(function (res) {
});
My C# Controller
namespace Reporting.api
{
[Route("api/buyer")]
public class BuyersController : Controller
{
// POST api/buyer
[HttpPost]
public string Post([FromBody] string Url)
{
return Url;
}
}
}
I've tried setting the data as "JsonResult data", or even "string Url." Most tutorials I found had an object for the data so it would fit into something like "[FromBody] Buyer buyer" but I don't have an object for it, I simply want the data. Is it possible?
WebApi does not support multiple parameter binding from a post request. You can check more details here.
So the proper way for the WebApi is to create a request model that will contain all the properties that will be bound. Perhaps you can try multiple [FromUri] parameters, but then you will have to add them to the url yourself in angualr, rather than just pass to .post.
Example model:
public class RequestModel
{
public string Url {get;set;}
public string Name {get;set;}
}
I also believe that adding the model improves the structure of your code as you always know what your server expects rather than working with some dynamic data.
P.S. Did not notice that you use ASP.Net Core, my data is from web api 2, but perhaps it's still valid, so you will need to create a model + FromBody should not be required on post requests since it's the default behavior.
I think your controller is wrong. You are trying to pass a Url and a name whereas your controller method is waiting for a single Url.
Try to pass only a Url and it should work.
If you want to pass the Url and the Firstname, you have to modify your controller method like this :
[HttpPost]
public string Post([FromBody] string Url, string FirstName)
{
// Do whatever you need to do here ...
}
I have created POST/GET request in MVC before.
In my HomeController
[HttpPost]
public string Index(int Value)
{
return Value.ToString();
}
And setting chrome extension POSTMAN with a form-data
I can call http://localhost/mvcApp/ with a variable 'Value' with value '1' and get a string '1' in return
But when I create a surveyController : ApiController doesn't work when I call http://localhost/mvcApp/api/survey/
public string Post(int Value)
{
return Value.ToString();
}
"Message": "No HTTP resource was found that matches the request URI 'http://localhost/mvcApp/api/survey/'.",
"MessageDetail": "No action was found on the controller 'survey' that matches the request."
I'm not sure if the error is in the way the api is created, or in the way the POSTMAN is trying to call the api. Because that '.'
Also try in my HomeControler Index
client.BaseAddress = new Uri("http://localhost/mvcApp");
var result = client.PostAsync("/api/survey", new
{
Value = 1
}, new JsonMediaTypeFormatter()).Result;
if (result.IsSuccessStatusCode) // here return Not found
The WebApi controllers' conventions are not the same as those of plain ol' MVC controllers.
Basically the problem is that you can't specify the int parameter the way you did.
Try this in you WebApi controller:
// nested helper class
public class PostParams {
public int Value { get; set; }
}
public string Post(PostParams parameters) {
return parameters.Value.ToString();
}
and see how that works.
Here's a thorough article on passing parameters within POST requests to WebAPI controllers:
Passing-multiple-POST-parameters-to-Web-API-Controller-Methods
Long story short, these are the conventions, roughly speaking:
you can't capture POST form name-value pairs in parameters
you can capture them inside the properties of a class if that class is the parameter type of one of your method's parameters
you can capture query parameters in method parameters
EDIT
If you wish to test your WebAPI server using C# you could follow these steps:
Create a nice Console Application (preferably within the same solution)
Add the Web API Client NuGet package to this Console Application
Make your Program.cs do something like this.
The following code uses the C# 5.0 async and await operators.
It also uses the Task class and anonymous types.
I've pointed out official MSDN articles (click on the links) should you be interested in what those things are.
using System.Net.Http;
using System.Threading.Tasks;
namespace ConsoleApplication1 {
class Program {
public static void Main(string[] args) {
Test().Wait();
}
private static async Task Test() {
HttpClient client = new HttpClient();
await client.PostAsJsonAsync(
"http://localhost/mvcApp/api/survey/",
new {
value = 10
}
);
}
}
}
This wasnt easy. After lot of reading I solve it like this.
First the api controler need to define the input parameter with the [FromBody] attribute
// POST api/survey
public void Post([FromBody]string value)
{
}
For testing I put a button in the view and use an Ajax / Post, the variable name need to be an empty string before the variable value.
$(document).ready(
$('#post').click(function () {
var url = 'http://localhost/mvcApi/api/survey';
var data = { "": 'Hola' }; // Define a simple variable this way
$.ajax({
type: "POST",
url: url,
data: data,
success: sucess
}
});
})
Or if you want send mutliple values
data = { "": ["update one", "update two", "update three"] };
But if you want receive an object
public void Post(Survey data)
{
string value = data.Value.ToString();
}
$('#post').click(function () {
....
var data = { value: 25 }
More info here Sending Data and here Binding
In the angular controller I have this code to transfer $scope.myModel to a Web API controller:
$scope.upload[index] = $upload.upload({
url: settings.constants.uploadURL,
headers: { 'myHeaderKey': 'myHeaderVal' },
data: { model: $scope.myModel },
file: $file,
fileFormDataName: 'myFile'
}).then(function (response) { ...
The Web API controller post method looks like this
public HttpResponseMessage Post()
{
return UploadFile(HttpContext.Current);
}
How do I get the data: model from out from the HttpContext??
WebAPI is not designed to be used in that fashion. Specifically, it is usually bad practice to refer to HttpContext.Current from within a WebAPI controller method. If you did want to check the request or response, you should refer to them by the properties of the ApiController base class, see the msdn docs.
Usually, people prefer model binding for situations like this. Suppose you had in js:
{
foo: "bar"
}
You should declare a class in C# that maps to it:
public class MyRequestModel
{
public string Foo { get; set; }
}
And by declaring your API method:
public HttpResponseMessage Post(MyRequestModel mdl)
{
// do stuff, mdl.Foo will have "bar" in it magically
}
This results in more object-oriented ways of transferring data from javascript to C#. It's more typesafe because you can be guaranteed that the Foo property in C# will have a string, or an int, or whatever you declare it to be as opposed to parsing the request yourself.