Why do I need FromBody Attribute when expecting data in POST body - angularjs

I can send my data to the server but ONLY when I use the FromBody-Attribute.
Why is the json data not automatically read from the Body using a Post?
Backend web api
[HttpPost]
public async Task<IActionResult> Post([FromBody]CreateSchoolyearRequestDTO dto)
{
}
Frontend angularjs
this.createSchoolyear = function (schoolyear) {
var path = "/api/schoolyears";
return $http({
url: path,
method: "POST",
data: schoolyear,
contentType: "application/json"
}).then(function (response) {
return response;
});
};

Just because something is a POST request, there is no clear rule how arguments are being transferred. A POST request can still contain query parameters encoded in the URL. A method parameter is expected to be a query parameter for “simple” types (strings, ints, etc.).
Complex types are usually expected to be POST form objects. The standard ASP.NET POST request is a form submit, e.g. when logging in. The parameters in those request are usually encoded as application/x-www-form-urlencoded, basically a string of key/value pairs. For complex parameter types, e.g. form view model objects, this is assumed the default.
For all other non-default situations, you need to be explicit where a method parameter comes from, how it is being transferred in the request. For that purpose, there are a number of different attributes:
FromBodyAttribute – For parameters that come from the request body
FromFormAttribute – For parameters that come from a single form data field
FromHeaderAttribute – For parameters that come from a HTTP header field
FromQueryAttribute – For parameters that come from a query argument encoded in the URL
FromRouteAttribute – For parameters that come from the route data
FromServicesAttribute – For parameters for which services should be injected at method-level

Related

React Fetch POST removes characters with header Content-type = application/x-www-form-urlencoded

I am using react with fetch for sending an image to the server.
I have tried using Content-type = application/x-www-form-urlencoded to pass my data to the server but it replaces special characters with spaces (i.e. + becomes a space).
I have switched the header to be Content-type: multipart/form-data but that throws the error
Failed to load resource: the server responded with a status of 500
(Internal Server Error).
I have added a boundary to the Content-type as boundary=abcdefg.
That did not change anything and I am not sure what my boundary would be.
Finding a clear answer with straight forward examples about boundaries have been impossible to get.
The data that I am sending is a large string.
If needed I can post that as well.
Here is a sample of the code that is causing the problem:
SaveTest4(data: string) {
const options = {
method: 'post',
headers: {
"Content-type": "multipart/form-data; boundary=abcdefg"
},
body: 'data=' + data
}
fetch('api/DataPoint/AddTest4', options);
}
Based on part of your analysis, it sounds like you're trying to send base64-encoded data. A content type of application/x-www-form-urlencoded will result in the server performing URL decoding, which will replace each instance of + in the content body with a space character.
When you used a content type of multipart/form-data, the server fails with status 500 because the data you provided wasn't a properly constructed MIME document.
My psychic debugging powers tell me that you're trying to post a base64-encoded file to a ASP.NET MVC WebAPI endpoint that's expecting a JSON document. You might have a controller method that looks like this:
[HttpPost("api/DataPoint/AddTest4")]
public void AddTest4([FromBody] string data) { ... }
If you send with a content type of application/json, this endpoint will expect a document that looks like this:
"{base64-encoded-data}"
Note that there are quotes around the data, because a quoted string is a proper JSON document. You'd just use JSON.stringify() to create the quoted string in this case, which would escape any quotes within the string correctly.
If you send with application/x-www-form-urlencoded, you'd need to send a document that looks like this:
data={base64-encoded-data}
But, as you note, you'd have to make sure you escape all of the special characters in the payload; you can do this using window.encodeURIComponent(), which would translate each "+" to "%2B", among other things.
If the files that you're uploading to this endpoint are large, it would be significantly better to use an instance of FormData. This would allow the browser to stream the file to the server in chunks instead of reading it into memory and base64-encoding it in JavaScript.

How to use / in parameter during rest webservice call from angularjs?

I need to send a value like app/role as parameter through rest webservice url from angularjs
In controller.js
var roleName = 'app/role';
checkRole.check({'roleName': roleName}, function(data){}
In model.js
popModel.factory('checkRole', function ($resource) {
return $resource('./rest/checkRole/:roleName',{roleName:'#roleName'},{
check: {'method':'GET'},
});
});
The rest webservice call in java
#GET
#Path("/checkRole/{roleName}")
#Produces(MediaType.APPLICATION_JSON)
public Response checkRole(#Context HttpServletRequest request, #PathParam("roleName") String roleName);
When i pass it i am getting browser console error as
Bad request response from the server.
For normal parameter values like 'Test', 'Solution', 'Application' etc. If i use with / as a parameter no process is done and i am getting error.
/ is reserved character for GET request. So, you can't use them directly. If you use them, you would get Bad Request Error.
One of the solution can be to encode the URL on client side and decode it on server.
Reference:
Characters allowed in GET parameter
How to handle special characters in url as parameter values?

Angular: set Content-Type per query

I need to perform one query with Content-Type different than application/json.
Changing default $http options is not a variant, because a lot of queries still be performed with JSON data.
I've found example
var req = {
method: 'POST',
url: 'example.com',
headers: {
'Content-Type': "application/x-www-form-urlencoded"
},
data: "somedata"
}
$http(req).then(function (resp) { console.log(resp);});
But it don't want to work — Content-Type is still a application/json.
Is any true way to do it right? Changing $http defaults and then restoring is not a solution.
What you are doing is not a valid way to set headers in angularjs.
To add or overwrite these defaults, simply add or remove a property
from these configuration objects. To add headers for an HTTP method
other than POST or PUT, simply add a new object with the lowercased
HTTP method name as the key, e.g. $httpProvider.defaults.headers.get =
{ 'My-Header' : 'value' }.
Ref. https://docs.angularjs.org/api/ng/service/$http - "Setting HTTP Headers" section
Edit.
What you're doing is right but you're missing one thing.
In your scenario it does not work because when using application/x-www-form-urlencoded you need to encode your data using $httpParamSerializerJQLike(). Also remember to put $httpParamSerializerJQLike as dependency.

I am uploading the image file in Angular Js to call the java api but my form data is not hitting the api

controller:
$scope.fileToUpload = function(input) {
if (input.files && input.files[0]) {
CommonService.uploadContactImage.upload({
fileName : input.files[0].name
}, input.files[0], function(data) {
});
}
}
Service:
uploadContactImage:function(input){
console.log("game image");
var req = $http({method: 'POST', url: options.api.base_url + '/gameimageupload/',
dataType: 'json', headers: {'Content-Type': undefined}})
.success(function (data)
{
console.log("data" + data);
return data;
});
If you take a good look at your code you will see that there are quite a few things wrong with it. For example, you have defined in your service an uploadContactImage function which takes a single Javascript object as argument (input), while in your controller you attempt to call CommonService.uploadContactImage.upload(...) instead of CommonService.uploadContactImage(...). Additionally, even if the uploadContactImage function was called correctly it doesn't actually do anything with its argument, ie. the input object is never used in the function body.
These issues aside you cannot submit a file to the server just by adding it to the body of a POST request the way you (seem to be) trying to do. Without going into too much detail here, in order to upload a file from the browser a request with content type multipart/form-data needs to be submitted, which will contain your file as well as the necessary HTTP headers for the server to identify it and parse it correctly. I suppose you could try and construct this request yourself, however it's not a task for the faint-hearted. What I would suggest instead is to use one of the many file upload modules available for Angular.js. A Google search will give you quite a few modules that you can check out to see which better fits your needs.

Chrome extension data connection to server

I would like to connect my Chrome Extension to my server, and send data back and forth. In particular, when the user clicks a button on the extension when he's navigating a certain URL, the server checks its database to see how many times that URL has been clicked, increment the count, and send the new count back to the user.
I know that sending the data to the server is possible with an AJAX request, but what about getting the data back from the server?
I think, you may use AJAX for getting updated count in a straightforward manner. For example (with jQuery):
$.ajax({
url: 'ajax/count.php?url=' + encodeURIComponent(newURL),
// dataType: 'json',
success: function(data) {
// parse you data received from server here
// data.count
}
});
So you can "send" new info as parameters of GET request, and get required information from server as http-response. The type of the data used to transfer the count is up to you. For example, this can be json (jQuery provides a shorthand method getJSON, which does the same customized ajax call).
If you don't want GET, you may use POST and specify data as follows:
$.ajax({
type: "POST",
url: "ajax/count.php",
data: { url: newURL },
success: function(data){
// ...
}
});
You will obviously need to use xhr / ajax
But with the present chrome-extension API you might get an error like this
No 'Access-Control-Allow-Origin' header is present on the requested resource.
In order to get around this problem one can simply put the link to the server on the permission array in manifest.json
"permissions": [
"tabs",
"http://www.myserver.dom"
],
For more detailed description see this documentation by Google

Resources