I'm working with my project where using Asp.net with c# and Javascript.
I have my controller set up with c# where it accepts an object, and two additional variables. It is a HttpPost request, and it works fine until I added the additional variables. I've used console.log in my fetch json function to check that i truly get the desired values, which I am.
This fetch works fine with postman!
I've also tried swiching places on the Rented object, so that it is in the last position, if the Body of fetch was sent in last aswell, but it did not work.
This is what I get back when calling the function in my chrome browser:
https://localhost:44363/rent/save?movieId=2&maxRents=3 Status = 400
Feels like I'm missing something very basic here, maybe you can't send both variables and body at the same time with a request?
Here's the controller code:
[HttpPost("save")]
public ActionResult<Rented> SaveRent(Rented newLoan, int movieId, int maxRents)
{
var amountOfRent = _appDbContext.Rents.Where(m => m.MovieId == movieId);
if (maxRents <= amountOfRent.Count())
{
_appDbContext.Rents.Add(newLoan);
_appDbContext.SaveChanges();
return newLoan;
}
else
{
return BadRequest();
}
}
And here's the Fetch function:
function addToStudio(element) {
var movieId = element.id;
var studioId = element.value;
var maxRents = element.name;
var newId = Number(movieId);
var newStudioId = Number(studioId);
console.log(maxRents);
fetch('https://localhost:44363/rent/save?movieId=' + movieId + '&maxRents=' + maxRents, {
method: 'POST',
body: JSON.stringify({
studioId: newStudioId,
movieId: newId
}),
headers: {
"Content-type": "application/json; charset=UTF-8"
}
})
.catch(err => console.error("response-error", err))
.then(response => response.json())
.then(json => console.log(json))
.catch(err => console.error("json error", err))
container.innerHTML = `<h1>Saved</h1>`
}
I can see a couple of problems here:
You are using both the body of the request and in the URL query.
You're missing some important attributes in the control method signature .
I personally always try to use a single approach (either body or URL query). I find that it keeps the code more readable and is less bug-prone.
First of all, decide how you want to pass the data:
Through the request body
In the URL query
Mixed approach
Then write your methods accordingly.
In the body
The easiest approach is encapsulating your information in a .Net object and Jsonify its fields in the JavaScript:
public class RentDetails
{
public int MovieId {get; set;}
public int MaxRents {get; set;}
public Studio {get; set;} // you can also use objects, deserializing the Json will fill them as well.
}
Then you want to specify in the signature of your method that you are receiving a RentDetails in the body of the request.
[HttpPost("save")]
public ActionResult<Rented> SaveRent([FromBody] RentDetails rentDetails) { ... }
And lastly, you want the Jsonified body to reflect the object that should be received (pay attention to field names):
const request = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
movieId : movieID,
maxRent : maxRent,
studio:
{
// nested fields for nested objects
}
})
};
If you follow these steps, your controller will automatically deserialize the json in the body to the object and it will be ready for you to use.
In the URL Query
This is easier to handle but might grow to be messy.
Concatenate the fields in the javascript how you were already doing:
const link = baseLink.concat('?movieId=', movieId, '&maxRent=', maxRent, ...);
const result = await fetch(link); // no request is needed here, you already have all you need.
And then access those fields from the controller:
[HttpPost("save")]
public ActionResult<Rented> SaveRent() //<- no parameters are needed here
{
var allUrlKeyValues = HttpUtility.ParseQueryString(Request.QueryString.Value);
var movieId = int.Parse(allUrlKeyValues["movieId"]);
var maxRent = int.Parse(allUrlKeyValues["maxRent"]);
....
// as you see you can only pass strings in this way
}
Mixed Approach
Of course you can opt for a mixed approach, just use a combination of the code above.
Note that the simpler, the better ;).
Related
I am using a Laravel blade.
My code below happens error when the size of item of textarea is huge.
I am looking for a way to solve it.
Everyone. How should I send a huge text to server?
How should I modify my codes?
Blade(JavaScript)
function sendByGet()
{
var items = document.getElementById("item").value;
var param = "?items="+items+"&id={{$id}}";
var url = {{(url)}} + encodeURI(param);
let result = fetch(url);
result.then(response => response.json()).then(
responceObject =>{
}
}
}
Controller PHP
public function receivebyGet(Request $request)
{
$lineArray = array();
$slipData = explode("\n", $request->items);
Error
the date is replaces <huge_text> (Actual data is text(5000 characters))
phpbladeName?id=01:270 GET https://test.com/test/send_by_get?&item=<huge_text> 414
sendByGet # confirmation?id=01:270
onclick # confirmation?id=0:244
VM142:1 Uncaught (in promise) SyntaxError: Unexpected end of JSON input
at phpbladeName?id=01
Move your data to the BODY
function sendByGet(url) {
const items = document.getElementById("item").value;
const param = encodeURI("?id={{$id}}");
fetch(url + param, {
method: 'GET',
headers: { 'Content-Type': 'plain/text' },
body: items,
})
.then(response => response.json())
.then( ... );
}
PHP Controller (assuming being Laravel)
public function receivebyGet(Request $request) {
$lineArray = array();
$slipData = explode("\n", $request->getContent());
...
}
Query size limit
As mentioned by Peter Krebs the maximum URL size (which includes the Query) is 2000 characters. So you cannot expect your system to reliably work if url is longher than 2000. Read more here.
GET body
As pointed out by Jabaa you should semantically choose the method, not technically. But this is something that has evolved over time (initially the GET body was supposed to be rejected/ignored) read more here. Hence you should consider it carefully and verify that all the parties involved (server, browser, proxies, cache) supports it properly. This is why oftentimes developers choose to violate semantics and use a POST method.
The function getClientData() gets called from one of the anchor tags in a grid's column. The anchor tag has a couple of Data-Tags which are passed to the code behind method. I have to perform some DB operation through these parameters but before that I wanted to make sure if this prototype would work.
This is how the anchor tag looks:
Show
This is my Javascript method:
function getClientData() {
//var dataValue = { "keyData": this.event.target.getAttribute("data-kt"), "valueData": this.event.target.getAttribute("data-kv")};
$.ajax({
type: "GET",
url: "Clients.aspx/GetClientData",
contentType: 'application/json; charset=utf-8',
data: JSON.stringify({ keyData: this.event.target.getAttribute("data-kt"), valueData: this.event.target.getAttribute("data-kv")}),
dataType: 'json',
error: function (error) {
alert(error.statusText);
},
success: function (result) {
alert("Success: " + result );
}
});
}
I put a break point here and it never gets triggered. This is my web method in the code behind file:
[WebMethod]
[ScriptMethod(UseHttpGet = false)]
public string GetClientData(string keyData, string valueData)
{
string result = string.Empty;
if (!string.IsNullOrEmpty(keyData) && !string.IsNullOrEmpty(valueData))
{
result = "Decrypted String!";
}
return result;
}
This is the URL that gets created for the POST request "http://localhost:60825/Clients.aspx/GetClientData?{%22keyData%22:%22Cpuqsrtsotmfegrhsi-jikdbCvuwsxtcodmeelrmI-Dn-ovpcqSresctrfegthKiejy%22,%22valueData%22:%221p7q9%22}". Please let me know if I am doing something wrong.
I am not sure how you configured routing but based on your API method (code behind) your data should be formatted in following manner:
Method 1:
http://localhost:60825/Clients.aspx/GetClientData?keyData=Cpuqsrtsotmfegrhsi-jikdbCvuwsxtcodmeelrmI-Dn-ovpcqSresctrfegthKiejy&valueData=1p7q9
As you can see, instead passing stringified JSON object I am sending data in format of query string where keyData and valueData has corresponding values.
Method 2:
If you prefer to send stringified JSON you can modify your Payload in URL like this:
http://localhost:60825/Clients.aspx/GetClientData?data=%7BkeyData%22%3A%22Cpuqsrtsotmfegrhsi-jikdbCvuwsxtcodmeelrmI-Dn-ovpcqSresctrfegthKiejy%22%2C%22valueData%22%3A%221p7q9%22%7D
Here I am sending stringified JSON as data parameter in query string. For that purpose your code behing method needs to be like this:
[WebMethod]
[ScriptMethod(UseHttpGet = false)]
public string GetClientData(string data)
{
string result = string.Empty;
if (!string.IsNullOrEmpty(keyData) && !string.IsNullOrEmpty(valueData))
{
result = "Decrypted String!";
}
return result;
}
I have came and left this problem numerous times while trying to make my web apps and have gotten fed up with no results, to the point that I have to ask here, so please excuse me if I come off as venting... I am quite aggravated.
I am trying to send data in the form of key-value pairs from my client(vanilla js) to my back end(spring boot java). I have tried numerous ways of doing it but can't seem to find the correct way/combination to achieve what I want done. My current non-working code is as follows.
Client-Side JS
var object = {
'id' : 1,
'username' : 'jumpthruhoops',
'password' : 'melodysteez'
};
Axios
.post('http://localhost:8080/gameSchedule', JSON.stringify(object))
.then((response) => {
console.log(response.data);
});
Back-End Spring Boot/Java
#CrossOrigin
#RequestMapping(value = "/gameSchedule", headers = "Accept=application/json", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public String getSchedule(#RequestBody String user) {
System.out.println(user);
return "test";
}
The following code is what I currently have that has given me any type of results close to what I'm looking for. It gives me the following printed line...
%7B%22id%22%3A1%2C%22username%22%3A%22tdellard1%22%2C%22password%22%3A%22sisters3%22%7D=
...which I believe is a hex code for the string object I passed into the parameter. I'm not sure if this is from Spring Boot, or if this is what JSON.stringify does. Since the User Object is a test object and actual object that I plan on passing in, is way more complex, I don't want to figure out how to decode the hex code, unless I can't get anything else going and I completely have to.
Because it is more complicated, I don't want to use a lot of #RequestParams("name") String VaribleName like 40 times in the parameter of the method. This was also the only other way to get results but passing those variables into a url is maddening.
Some other things I have tried are #ModelAttribute and (#RequestBody User user), both return errors, one that seems to be reoccurring is
018-10-30 23:38:29.346 WARN 12688 --- [io-8080-exec-10] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/x-www-form-urlencoded;charset=UTF-8' not supported]
So what I am pretty much asking is for guidance on what is the best way to send my data from Axios(form.serialize, JSON.stringify, JavaScript Object, etc.) and what corresponding method I need to use to obtain that data on my Spring Boot Back-End and make it manipulative so I can turn it into a POJO.
Just remove JSON.stringify(object) and put object.
Axios
.post('http://localhost:8080/gameSchedule', object)
.then((response) => {
console.log(response.data);
});
You can see an example on POST request here axios documentation
On Spring boot you have to create an entity like this:
#Entity
public class UserAccount implements Serializable {
#Id
private Long id;
#Column(unique = true, nullable = false)
#Size(max = 255)
private String userName;
#Column(nullable = false)
#NotNull
private String password;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
and change your code for here
#CrossOrigin
#RequestMapping(value = "/gameSchedule", headers = "Accept=application/json", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public UserAccount getSchedule(#RequestBody UserAccount user) {
System.out.println(user.getUserName());
return user;
}
If you are sending an object you have to use object when receiving at back-end side and make sure that name of the field in request object and the field name of the class at back-end side must be same,
so it should be like this:
I am just making some changing in your code to access field:
var data = {
'id' : 1,
'username' : 'jumpthruhoops',
'password' : 'melodysteez'
};
// name of variable(data variable) doesn't matter but inside everything consider as a body
axios.post('http://localhost:8080/gameSchedule', JSON.stringify(object), {
headers: {
'Content-Type': 'application/json',
}
}
);
back-end side retrieve fields
//create one Student class to map fields with body
#CrossOrigin
#RequestMapping(value = "/gameSchedule", headers = "Accept=application/json", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public String getSchedule(#RequestBody Student student) {
System.out.println(student.id);
System.out.println(student.username);
System.out.println(student.password);
return "test"
}
I'm trying to call a controller method that will save my object, but when i try to url to it, it returns http error. I've browsed through some similar problems on SO but no luck. So i wanna ask myself...
Here is my Ajax (for simplicity purposes i renamed the variables):
function addDob() {
var var1 = $("#var1").val();
var var2 = $("#var1").val();
var var3 = {};
var3["var3"] = $("#var3").val();
var json = JSON.stringify({
var1 : var1,
var2 : var2,
var3 : var3
});
console.log(json);
alert(json);
$.ajax({
url: 'add_dob',
type: 'POST',
contentType: 'application/json; charset=utf-8',
dataType: json,
success: function (data) {
console.log(json);
alert(data.message);
resetForm();
},
error: function () {
alert("Error!");
}
});
}
Here is my controller:
#RequestMapping(value = "/add_dob", method = RequestMethod.POST, produces = "application/json")
#ResponseBody
public Map<String, Object> saveDob(#RequestBody DobavljacWrapper wrapper) {
Map<String, Object> data = new HashMap<>();
Dob d = new Dob();
d.setCountryID(wrapper.getCountryID());
d.setDobName(wrapper.getDobName());
d.setYear(wrapper.getYear());
dobService.save(d);
data.put("message", "Dob was successfully saved!");
return data;
}
Any suggestion is welcomed. If i need to insert any more info, just let me know. Cheers! P.S. I had a similar project that works, but my model classes were different, so i suspect there's something to it..
UPDATE 1.0:
I figured out it has a lot to do with the #RequestBody parameter.
That parameter matches the one you are pushing through with your Ajax. Now, I need that parameter to match my object which has the exact attributes I am passing through with Ajax. Somewhere in there i am making a mistake, and i'm not sure what exactly is the right way here...
If i set "#RequestBody String someString" it will return the parameters i pushed with ajax, but i won't be able to access that info with the getters 'cause it's a string. So i need an object to collect those values!
The answer was the Wrapper class.
It couldn't assign values to it and threw error because i set attributes to "private".
Setting them "public" solved it for me.
Can't believe that was the error...
First off, I'll acknowledge there are lots of questions close to my one here, but having tried every solution I can find on SO I'm still stuck.
My Service method within my service.js is as follows, with comments;
postSimpleObject: function () {
// Have tried this first, and have passed
// as JSON.stringify(simpleObject)
var simpleObject = {
name: "J Doe",
colour: "Red"
};
// tried to pass this next
var simplerObject = '{ "Name": "J Done", "Colour":"Red"}';
// escaped the quotations and tried this next
var simplerObject2 = '{ \"Name\": \"J Done\", \"Colour\":\"Red\"}';
return $http.post(apiUrl + "PostSimpleObject?item=" + JSON.stringify(simpleObject), {
headers: {
'Content-Type': 'application/json'
}
});
}
Here is my API controller function on the API side;
public class CrudUserApiController : ApiController
{
[System.Web.Http.HttpPost]
public void PostSimpleObject(SimpleObject item)
{
var itemReceived = item;
}
}
my simple object class, on the api side;
public class SimpleObject
{
public string Name { get; set; }
public string Colour { get; set; }
}
Now, what happens is;
The API method is triggered, the routing can locate the controller and method
The model / object received is a new SimpleObject with null properties for both members
As per the comments in the service, I've tried passing a stringified object, a json string and an escaped json string.
Also on the API side I've tried using the [FromBody] attribute in front of the SimpleObject argument in the signature. The same thing happens.
I'm totally lost, some help would be much appreciated. Thanks.
It would be advisable to post the content on the body instead of on the the querystring for a number of reasons, such as querystring length limitations.
That said, if you insist on using the querystring, you need to tell WebAPI to look to the querystring for the data using the FromUri attribute, since the default is the body:
[System.Web.Http.HttpPost]
public void PostSimpleObject([FromUri]SimpleObject item)
{
var itemReceived = item;
}
Alternatively, you can post the content on the body directly as called out by ex0dm3nt:
$http.post(apiUrl + "PostSimpleObject", simpleObject);
You just need to pass your simpleObject as second parameter in the $post request like this:
postSimpleObject: function () {
var simpleObject = {
name: "J Doe",
colour: "Red"
};
return $http.post(apiUrl + "PostSimpleObject", simpleObject);
}