So actually everything is working well, except the fact that i can't get access to "inscrit" which is supposed to be the one which is sent to have the information user
This is my function in javascript and it does go into success for ajax.
function fbLogin() {
FB.login(function (response) {
if (response.authResponse) {
var inscrit = {
"prenom": response.first_name,
"nom": response.last_name,
"email": response.email
}
$.ajax({
method: 'post',
url: '/hello/facebookconnection',
contentType : 'application/json; charset=utf-8',
data: JSON.stringify(inscrit),
datatype: "json",
success: function() {
window.alert('User data sent');}
,
error: function(){
window.alert('Error in sending ajax data');}
});
} else {
document.getElementById('status').innerHTML = 'User cancelled login or did not fully authorize.';
}
}, {scope: 'email'});
}
And this is my java controller (whatever i do, the "inscrit.getEmail()" is always null)
#RequestMapping(value = "/facebookconnection", method = RequestMethod.POST)
#ResponseBody public void createUser(#RequestBody inscrit inscrit, ModelMap model) throws Exception {
//System.out.println(inscrit.getNom());
//System.out.println(inscrit.getPrenom());
System.out.println(inscrit.getEmail());
try {
user.adduser(inscrit);
} catch (Exception e) {
e.printStackTrace();
}
}
This is my inscrit class with all the getter and setter correctly set (i know that there's no problem with it)
#Entity
#Table(name="inscrit")
public class inscrit implements Serializable {
#Id
#Column(name="email")
private String email;
#Column(name="nom")
private String nom;
#Column(name="prenom")
private String prenom;
}
So i would like to know if someone could help me understand why it's not working in my controller (how to do so the data is sent properly from the ajax to the controller) :(
Thx !
EDIT : i did write the answer of that question below. The problem was the fact that response.first_name was really blank... and had to pass through the function userdata() which had the real informations. So that means i don't have any real error in my code, all the informations between the controller and my jsp page works correctly. Be free to use it as an example of how this works
#ResponseBody public void createUser(#RequestParam(value="inscrit") String inscrit) throws Exception {
//System.out.println(inscrit.getNom());
//System.out.println(inscrit.getPrenom());
Inscrit ins = JSON.parseObject(inscrit, Inscrit.class);
System.out.println(ins.getEmail());
try {
user.adduser(ins);
} catch (Exception e) {
e.printStackTrace();
} }
The class of inscrit.java is nonstandard.You should change it to Inscrit.java.
I hope this helps.
I'll answer to my own question since i found the answer, So this is for people who tries to have a facebook api and want to get informations of the profil to put into database.
My error was the fact that i thought response in login was the same asthe UserData(), which is not the case... So that's how i was supposed to do it.
function fbLogin() {
FB.login(function (response) {
if (response.authResponse) {
// Get and display the user profile data
getFbUserData();
} else {
document.getElementById('status').innerHTML = 'User cancelled login or did not fully authorize.';
}
}, {scope: 'email'});
}
// Fetch the user profile data from facebook
function getFbUserData(){
FB.api('/me', {locale: 'en_US', fields: 'id,first_name,last_name,email,link,gender,locale,picture'},
function (response) {
/*document.getElementById('fbLink').setAttribute("onclick","fbLogout()");
document.getElementById('fbLink').innerHTML = 'Logout from Facebook';
document.getElementById('status').innerHTML = 'Thanks for logging in, ' + response.first_name + '!';
document.getElementById('userData').innerHTML = '<div class="fbprofile"><p><b>FB ID:</b> '+response.id+'</p><p><b>Name:</b> '+response.first_name+' '+response.last_name+'</p><p><b>Email:</b> '+response.email+'</p><p><b>Gender:</b> '+response.gender+'</p><p><b>Locale:</b> '+response.locale+'</p></div><p><b>Picture:</b> <img src="'+response.picture.data.url+'"/></p>';*/
var inscrit = {
"prenom": response.first_name,
"nom": response.last_name,
"password": "1234",
"status": 0,
"email": response.email
}
$.ajax({
method: 'post',
url: '/hello/facebookconnection',
contentType : 'application/json; charset=utf-8',
data: JSON.stringify(inscrit),
datatype: "json",
success: function() {
document.location.href = "accueilmember";
},
error: function(){
window.alert('Error in sending ajax data');}
});
});
}
This is my controller class.This just logs the post request send to the server:(You may modify this if you need something more like adding a Response Body)
#RestController
public class EmailController {
#RequestMapping(value = "/facebookconnection", method = RequestMethod.POST)
public void createUser(#RequestBody inscrit inscrit) throws Exception {
System.out.println(inscrit.getNom());
System.out.println(inscrit.getPrenom());
System.out.println(inscrit.getEmail());
}
This is my inscrit.java class(I personally think naming the class would not affect but better follow standard naming Practices like Inscrit.java)
import java.io.Serializable;
public class inscrit implements Serializable {
private static final long serialVersionUID = -8445943548965154778L;
private String email;
private String prenom;
private String nom;
public inscrit() {
super();
}
public inscrit(String email,String prenom,String nom) {
this.setEmail(email);
this.setPrenom(prenom);
this.setNom(nom);
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getNom() {
return nom;
}
public void setNom(String nom) {
this.nom = nom;
}
public String getPrenom() {
return prenom;
}
public void setPrenom(String prenom) {
this.prenom = prenom;
}
}
I did a post request from Advanced Rest Client and set the payload as
{
"email":"agdfae#gmail.com",
"prenom":"qewrwe",
"nom":"qwer"
}
the results were
qwer
qewrwe
agdfae#gmail.com
You can modify this to suit your own needs.Hope this helps
EDIT:
You will need more two classes in spring boot as below:
ServletInitializer.java
public class ServletInitializer extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(PostDataApplication.class);
}
}
PostDataApplication .java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class PostDataApplication {
public static void main(String[] args) {
SpringApplication.run(PostDataApplication.class, args);
}
}
PostDataApplication is the name of the application.
These four classes will do the trick (with pom.xml only no other xml configuration needed since this is springboot).Let me know if you have any problem.
Related
I am using spring boot and I have simple form ,where there is upload option to upload the image.
<form>
<div class="col-md-6">
<input type='file' id="imgInp" />
<img id="blah" src="#" alt="your image" width="200" height="200" />
</div>
<button type="submit" id="btn-add" class="btn btn-primary btn-lg">Add Employee
</button>
</form>
When I upload the image,then it is changed into base 64 as below codes and it is manipulated in employee object and sent through AJAX post method.But I am getting error in spring boot side:
var imgObject;
$(document).ready(function() {
$("#imgInp").change(function() {
readURL(this);
});
function readURL(input) {
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function(e) {
$('#blah').attr('src', e.target.result);
console.log("aaaa");
imgObject = e.target.result;
console.log(imgObject);
}
reader.readAsDataURL(input.files[0]);
}
}
$('#btn-add').on('click', function() {
//stop submit the form, we will post it manually.
event.preventDefault();
console.log("hitted");
fire_ajax_submit();
});
});
function fire_ajax_submit() {
var employee = {
"iNumber": $("#iNumber").val(),
"fullName": $("#fullName").val(),
"joinedDate": $("#joinedDate").val(),
"position": $("#position").val(),
"reportsTo": $("#reportsTo").val(),
"cubicleNo": $("#cubicleNo").val(),
"jobType": $("#jobType").val(),
"imagObject": imgObject
};
console.log(employee);
$.ajax({
url: A_PAGE_CONTEXT_PATH + "/insert-emp",
method: "post",
contentType: "application/json",
dataType: "json",
data: JSON.stringify(employee),
success: function(response) {
console.log(response);
alert("Successfully Saved!");
window.location.reload(true);
},
error: function(response) {
switch (response.status) {
case 409:
alert("error");
}
}
});
}
console.log(employee) is printed as:
The image is converted into base64.
I tried to insert the image using AJAX.So, my Rest Api is:
#RestController
public class EmployeeController {
#Autowired
private EmployeeService empService;
#PostMapping("/insert-emp")
#ResponseBody
public Employee createEmployee(#Valid #RequestBody Employee employee){
return empService.saveEmployee(employee);
}
}
My service class is:
#Service
public class EmployeeService {
#Autowired
private EmployeeRepository empRepository;
public Employee saveEmployee(Employee employee){
if(employee.getId()==0){
empRepository.save(employee);
}
else{
empRepository.save(employee);
}
return employee;
}
My repository class is:
#Repository
public interface EmployeeRepository extends JpaRepository<Employee,Integer> {
}
My model Employee.java class is:
#Entity
#Table(name = "employee")
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#NotBlank
private String iNumber;
#NotBlank
private String fullName;
// #NotBlank
private String joinedDate;
#NotBlank
private String position;
#NotBlank
private String reportsTo;
#NotBlank
private String cubicleNo;
#NotBlank
private String jobType;
private byte[] imagObject;
public Employee() {
}
//all getters and setters
}
But I am getting error as:
w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type `byte[]` from String "image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAUEBAUEAwUFBAUGBgUGCA4JCAcHCBEMDQoOFBEVFBMRExMWGB8bFhceFxMTGyUcHiAhIyMjFRomKSYiKR8iIyL/2wBDAQYGBggHCBAJCRAiFhMWIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiL/wAARCAOWBmADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8]...[zUOSGGaKKfQfUUMSuR3NY3iCZ7WC3ky+3zQrBHKk8Hv9cUUUhMzv+Es8gLHLbsz/AN4P2/Kom8aQcj7NLke4ooplW0I9T1wvb20sbTQqZPm8vGTwcUtn4niS3WOaOVpAMMRg5P50UUE9BV8YWZyBDcDnH3V/xq3o2qLfmWP94SCWBfHQngUUUDGXGvwWskiSxSEx9SoH+NRr4hgctiKTAODwP8aKKQupONaiyN6Pg9MAf41Qi1mRb2Z3Zmi34CYHAoop20GbdvfLOrFVYY9ay4NUlW5l8470810C46YYj+lFFICWXUylwrHJiOBtxyDWgZRtVucHtRRTa0H0IzdBAcgmoReozHKtxRRSEthxuFwDtODQJAw70UUC6iH5Tx3prnauTk5oooH0IHnwxXHUAimbgeuaKKroJjzJ+74/WmRnI55zRRUCKMF68txIrqu0OVGOvBP+FXBz04ooprYZXEjNcNEcYA9KsoQqYxx0oopg9z//2Q==": Failed to decode VALUE_STRING as base64 (MIME-NO-LINEFEEDS): Illegal character ':' (code 0x3a) in base64 content; nested exception is com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type `byte[]` from String "image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAUEBAUEAwUFBAUGBgUGCA4JCAcHCBEMDQoOFBEVFBMRExMWGB8bFhceFxMTGyUcHiAhIyMjFRomKSYiKR8iIyL/2wBDAQYGBggHCBAJCRAiFhMWIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiL/wAARCAOWBmADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8]...[zUOSGGaKKfQfUUMSuR3NY3iCZ7WC3ky+3zQrBHKk8Hv9cUUUhMzv+Es8gLHLbsz/AN4P2/Kom8aQcj7NLke4ooplW0I9T1wvb20sbTQqZPm8vGTwcUtn4niS3WOaOVpAMMRg5P50UUE9BV8YWZyBDcDnH3V/xq3o2qLfmWP94SCWBfHQngUUUDGXGvwWskiSxSEx9SoH+NRr4hgctiKTAODwP8aKKQupONaiyN6Pg9MAf41Qi1mRb2Z3Zmi34CYHAoop20GbdvfLOrFVYY9ay4NUlW5l8470810C46YYj+lFFICWXUylwrHJiOBtxyDWgZRtVucHtRRTa0H0IzdBAcgmoReozHKtxRRSEthxuFwDtODQJAw70UUC6iH5Tx3prnauTk5oooH0IHnwxXHUAimbgeuaKKroJjzJ+74/WmRnI55zRRUCKMF68txIrqu0OVGOvBP+FXBz04ooprYZXEjNcNEcYA9KsoQqYxx0oopg9z//2Q==": Failed to decode VALUE_STRING as base64 (MIME-NO-LINEFEEDS): Illegal character ':' (code 0x3a) in base64 content
at [Source: (PushbackInputStream); line: 1, column: 143] (through reference chain: com.ashwin.vemployee.model.Employee["imagObject"])]
How can I handle this error?
This is not a standard approach. But try it.
#Entity #Table(name = "employee")
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
// Remaining fields
#Transient
private String imageDecode;
}
From UI send your decoded data to this transient variable.
Once after the successful serialization convert that string to byte array[].
byte[] byte = imageDecode.getBytes();
Hope this will work.
The stack trace shows the exact problem. Yes you cannot deserialize the String to byte array. To make your JSON deserialize works you need to create custom deserializer.
Reference:
https://www.baeldung.com/jackson-deserialization
Solved
I have been working on this program since 07:00. This has been driving me crazy. I have written multiple full stack web apps and have not had this problem.
Basically I have a form in html that allows a user to input data. Whenever the submit button is clicked, it sends that data to a collection in mongoDB. I have tested this in postman and it works. However, when I run the program through a webbrowser, I get this error:
XMLHttpRequest cannot load http://localhost:8080/articles/addArticle. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access. The response had HTTP status code 404.
I tried installing CORS and configuring the endpoint
I tried going into the javascript file and changing the
This is my JavaScript file
alert('JS is linked to page!');
function Article(id = 1, title = "", authors="", content = "", genre = "", date = 1497484623) {
console.log("JavaScript file loaded successfully");
var self = this;
self.Id = id;
self.Title = title;
self.Authors = authors;
self.Content = content;
self.Genre = genre;
self.Date = date;
self.Save = function() {
var settings = {
url: 'http://localhost:8080/articles/addArticle',
method: 'POST',
dataType: "json",
beforeSend: function (xhr) {
xhr.setRequestHeader("Accept", "application/json");
}
};
var myData = {
"Id" : self.Id,
"Title": self.Title,
"Authors": self.Authors,
"Content": self.Content,
"Genre": self.Genre,
"Date": self.Date
};
settings.data = myData;
$.ajax(settings).done(function(article) {
var myArticle = new Article(article.Id, article.Title, article.Authors,
article.Content, article.Genre, article.Date);
});
};
}
function addArticle(Article) {
alert('addArticle Activated');
var settings = {
url: 'http://localhost:8080/articles/addArticle',
method: 'POST',
dataType: "json",
beforeSend: function (xhr) {
xhr.setRequestHeader("Accept", "application/json");
}
};
var myData = {
"Title": Article.Title,
"Authors" : Article.Authors,
"Content": Article.Content,
"Genre" : Article.Genre,
"Date": Article.Date
};
settings.data = myData;
$.ajax(settings).done(function(Article) {
var myArticle = new Article(article.Id, article.Title, article.Authors, article.Content,
article.Genre, article.Date);
console.log("Article Created");
});
}
$(document).ready(function() {
$(document).on("submit", "#add-article", function(e) {
e.preventDefault();
alert('submit Activated');
var title, authors, genre, content;
title = $("#Title").val();
director = $("#Authors").val();
rating = $("#Genre").val();
notes = $("#Content").val();
var myArticle = new Article(0, title, authors, genre, content, 1497484623);
alert(myArticle.Title);
addArticle(myArticle);
$("#add-article")[0].reset();
$("#title").focus();
});
});
/*function CreateSuccessRow(Article) {
var successDataRow = `<tr id="Article-${Article.Id}"><td>${Article.Title}</td>
<td>${Article.Authors}</td>
<td>${Article.Genre}</td>
Due to popular demand, this is the server-side code:
package com.stereoscopics.app.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import com.stereoscopics.app.models.Article;
import com.stereoscopics.app.repo.ArticleRepo;
#RestController
#RequestMapping("/articles")
public class ArticleController {
private ArticleRepo articleRepo;
#Autowired
public ArticleController(ArticleRepo articleRepo) {
this.articleRepo = articleRepo;
}
#RequestMapping(value = "/findall", method = RequestMethod.GET)
#ResponseBody
public List<Article> findall() {
return articleRepo.findAll();
}
#RequestMapping(value = "/addArticle", method = RequestMethod.POST)
#ResponseBody
public Article addArticle(#RequestBody Article newArticle) {
articleRepo.save(newArticle);
return newArticle;
}
}
I have no idea how to fix this. Please help.
UPDATE
This still isn't working. I've updated the code as per some suggestions and I'm either doing it wrong or it's incorrect. The changes are shown below:
#RestController
#RequestMapping("/articles")
public class ArticleController {
private ArticleRepo articleRepo;
#Autowired
public ArticleController(ArticleRepo articleRepo) {
this.articleRepo = articleRepo;
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.addHeader("Access-Control-Allow-Origin", "*");
}
#RequestMapping(value = "/findall", method = RequestMethod.GET)
#ResponseBody
public List<Article> findall() {
return articleRepo.findAll();
}
#RequestMapping(value = "/addArticle", method = RequestMethod.POST)
#ResponseBody
public Article addArticle(#RequestBody Article newArticle, final
HttpServletResponse response) {
response.addHeader("Access-Control-Allow-Origin", "*");
articleRepo.save(newArticle);
return newArticle;
}
}
THIS IS NOT SOLVED YET
Basically what it says is that your service at
http://localhost:8080/articles/addArticle.
should add a header 'Access-Control-Allow-Origin' that the browser can read.
I ran to similar scenario when I was making a REST API, but instead of installing cors (which its version conflicts with our production server build), I just added that header when sending out responses to the request client.
response.AddHeader("Access-Control-Allow-Origin", "*");
If you are using asp.net, then you can either put that code in the Global.asax under:
protected void Application_BeginRequest(Object sender, EventArgs e) {
var context = HttpContext.Current;
var response = context.Response;
response.AddHeader("Access-Control-Allow-Origin", "*");
}
If you are using java/servlet/jsp then it's quite similar as you already have access to HttpServletResponse response so in your code body, just do:
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
response.addHeader("Access-Control-Allow-Origin", "*");
//other codes and stuff here...
}
from your code on the other hand which uses spring, you could do something like:
#RequestMapping(value = "/addArticle", method = RequestMethod.POST)
#ResponseBody
public Article addArticle(#RequestBody Article newArticle, final HttpServletResponse response) {
response.addHeader("Access-Control-Allow-Origin", "*");
articleRepo.save(newArticle);
return newArticle;
}
You can not solve cors as javascript end, I mean to say the problem is with your server code.
Cors is a security feature implemented by browser, let me tell you how it works.
when you query server, at first it hits with option method, at this time server sends allowed origins list, it can be one or multiple. now if your local domain or any domain is not present in that list then browser does not make the actual request.
To fix this you will have to configure cors filter on your server you can do it like
package com.package.filter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.GenericFilterBean;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
#Component
public class SimpleCORSFilter extends GenericFilterBean {
/**
* The Logger for this class.
*/
private final Logger logger = LoggerFactory.getLogger(this.getClass());
#Override
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException {
logger.info("> doFilter");
HttpServletResponse response = (HttpServletResponse) resp;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type");
//response.setHeader("Access-Control-Allow-Credentials", "true");
chain.doFilter(req, resp);
logger.info("< doFilter");
}
now if it's still not working then you will have to debug it line by line at server what's code, and at browser end you can test if option method has list of allowed origins or not.
I accidentally marked this as solved, when it clearly is not.
By including the port number in the Javascript url, the server threw an error because it mistook the request as originating from somewhere it wasn't supposed to come from. When I remove the port number, it doesn't know which port to hit. It should be hitting 8080 by default, but I'm getting another error.
To date, nobody has solved this problem. I've built apps without having this come up before and everyone I've asked at work seems to think I should just use spring forms. I'd ideally like to actually solve the problem instead of just finding work arounds.
Deal your CORS problem that you need to set the crossDomain first.
$.ajax({
crossDomain:true
})
Next, you gonna to set the xhrFields in withCredentials.
$.ajax({
crossDomain:true,
xhrFields: {
withCredentials: true
}
})
In you Code , it's look like following this setting config.
let settings = {
url: 'http://localhost:8080/articles/addArticle',
method: 'POST',
crossDomain:true,
xhrFields: {
withCredentials: true
}
dataType: "json",
beforeSend: function (xhr) {
xhr.setRequestHeader("Accept", "application/json");
}
};
I'm trying to post strings from an AngularJS application (using $http) to a server built on ASP.NET WebApi, but I get 404 as soon as I add a parameter.
The client code is this
$scope.add = function () {
// ...cut...
$http({ method: "POST", url: url, data: { fileString: "test string" }}).then(
function successCallback(response) {
$log.info(response.data);
}
);
}
The server code is
[HttpPost]
public IHttpActionResult UploadExcel(string fileString) {
// cut
}
I get a 404, but if I remove the parameter on server side it works, so i can use a server side code like this
[HttpPost]
public IHttpActionResult UploadExcel() {
// cut
}
What is wrong? Should I pass the data in a different way? I tried different combination but I can't get it work.
What you want to do is send a string, not a JSON object as you are doing right now with { fileString: "test string" }. When I want to send a string, what I normally do is that I send data from Angular like this:
$http.post("/Search/QuickSearch?searchQuery="+ searchString);
And my controller I make ready to receive a string like this:
[HttpPost]
public IHttpActionResult QuickSearch(string searchQuery)
{
// cut
}
If I want to send a JSON object, I tell my controller what it should expect, like this:
[HttpPost]
public IHttpActionResult SaveActivity(ActivityEditForm form);
{
// cut
}
public class ActivityEditForm
{
public int? Id { get; set; }
[Required]
public string Title { get; set; }
public string Description { get; set; }
}
And then send my JSON from Angular like this:
$http.post("/Activity/SaveActivity", { form: activity });
I suggest you should capture the request send by Angular. By default, Angular send parameters in a json string in request body.
I'm not sure wether Asp.net can parse them from json string in body.
So, you can try to add the below codes (also need jQuery)
angular.module('yourApp').config(function ($httpProvider) {
$httpProvider.defaults.transformRequest = function(data){
if (data === undefined) {
return data;
}
return $.param(data);
}
});
The first error is in the controller, [FromBody] should be used with the input parameter.
public IHttpActionResult UploadExcel([FromBody]string fileString)
Then the data variable on the client should be a single string, so
$http({ method: "POST", url: url, data: "test string" }).then(
Anyway I found some issue with this solution later, it seems the simplest but I suggest to avoid it.
Best solution
Thank to #Squazz answer and this SO answer I strongly suggest a change in the webapi controller, client was correct. Just introduce a class to handle a single string and adapt the input parameter
// new class with a single string
public class InputData {
public string fileString { get; set; }
}
// new controller
[HttpPost]
public IHttpActionResult UploadExcel([FromBody] InputData myInput) {
string fileString = myInput.fileString;
// cut
}
This way JSON code from the client is automatically parsed and it's easy to change the data input.
Extra tip
$scope.add angular function was correct as in the question, but here is a more complete example
$scope.testDelete = function () {
var url = "http://localhost/yourAppLink/yourControllerName/UploadExcel";
var data = ({ fileString: "yourStringHere" });
$http({ method: "POST", url: url, data: data }).then(
function successCallback(response) {
console.log("done, here is the answer: ", response.data);
}, function errorCallback(response) {
console.log("an error occurred");
}
);
}
I am having some issue submitting json data from jquery ajax. I have googled some similar problems but non of them worked for me.
$.ajax({
type : "POST",
contentType : "application/json",
url : "save-routes",
data : JSON.stringify(routeObject),
dataType : 'json',
timeout : 100000,
success : function(status) {
console.log("SUCCESS ADDING ROUTE DATA");
return status;
},
error : function(e) {
console.log("ERROR WHILE ADDING ROUTE DATA");
return false;
},
done : function(e) {
console.log("DONE");
//return true;
}
});
routeObejct Json format:
{name:"value", data:["value1","value2"...]}
spring controller:
#JsonView(Views.Public.class)
#RequestMapping(value = "/save-routes", method = RequestMethod.POST)
public #ResponseBody boolean loadRoutes(#RequestBody Route route) {
//codes
return status;
}
I keep getting this error:
POST http://localhost:8181/SYBusWebApp/save-route 400 Bad Request 6ms
Route Class:
public class Route {
#JsonView(Views.Public.class)
private String name;
#JsonView(Views.Public.class)
private ArrayList<stop> routeStops;
private String updatedRouteName;
private ArrayList<String> addedRouteStopNames;
//getters and setters
}
Stop Class:
public class Stop {
#JsonView(Views.Public.class)
private String name;
#JsonView(Views.Public.class)
private float latitude;
#JsonView(Views.Public.class)
private float longitude;
private String updatedName;
//getters and setters
}
It seems your Route object is not matching your JSON payload.
{name:"value", data:["value1","value2"...]}
In your case I would expect a nested collection of Stop objects within your JSON payload for routeStops:
{
name:"value",
routeStops:[
{
"name":"test",
"latitude": 3.124
},
....
],
...
}
I'm making an ASP.NET Web API web service, and an HTML/javascript page to test it. The issue I'm having is with passing a complex data parameter and having it come through properly in the web API controller.
I know there are numerous similar questions and I've read them and tried the solutions and haven't solved it. I have also read some JQuery documentation.
Here's my controller:
public class TitleEstimateController : ApiController
{
public IHttpActionResult GetTitleEstimate([FromUri] EstimateQuery query)
{
// All the values in "query" are null or zero
// Do some stuff with query if there were anything to do
}
}
public class EstimateQuery
{
// Various fields
}
The route mapping in WebApiConfig.cs:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{query}"
);
And the javascript:
var uri = 'api/titleEstimate/';
var query = {
"username": $("#user").val(),
// other fields
};
$.getJSON(uri,query)
.done(function (data) {
$('#product').text("OK");
})
.fail(function (jqXHR, textStatus, err) {
$('#product').text('Error: ' + err);
});
Currently I'm getting a 404. I tried $.getJSON(uri + '/' + query) but that didn't work either. Before I was passing this object I was calling it successfully so I think the routing is generally OK. I tried a type converter, but that didn't help, still a 404. Does anyone see what I'm missing/doing wrong?
Answer
You are using the wrong uri. You need api/titleEstimate/getTitleEstimate. That explains and will resolve your 404.
Answer to Follow Up Question
Everything else you're doing almost works. After you resolve the 404, you'll find that you aren't receiving the value FromUri, and you'll have a follow up question. So, you need to change your route config to this:
config.Routes.MapHttpRoute(
name: "Default",
routeTemplate: "api/{controller}/{action}"
);
Then you'll not only resolve your 404 but also receive the FromUri value that you're sending as query string parameters.
Demo
Here is a fiddle for evidence, which is calling into this controller, which is hosted LIVE here. The only thing I changed in the working version are the uri to resolve the 404 and the route config to make sure you receive the FromUri value. That's all.
HTML
<label>Username:
<input id="user" />
</label>
<button id="submit">Submit</button>
<button id="submit-fail">Submit Fail</button>
<div id="product"></div>
JavaScript
This will succeed.
Note, we only need domain because we doing cross-site scripting here for the demo purpose.
var domain = "https://cors-webapi.azurewebsites.net";
$("#submit").click(function () {
var uri = domain + '/api/titleEstimate/getTitleEstimate';
var query = {
"username": $("#user").val(),
// other fields
};
$.getJSON(uri, query)
.done(function (data) {
$('#product').text(data);
})
.fail(function (jqXHR, textStatus, err) {
$('#product').text('Error: ' + err);
});
});
This will 404.
$("#submit-fail").click(function () {
var uri = domain + '/api/titleEstimate';
var query = {
"username": $("#user").val(),
// other fields
};
$.getJSON(uri, query)
.done(function (data) {
$('#product').text(data);
})
.fail(function (jqXHR, textStatus, err) {
$('#product').text('Error: ' + err);
});
});
Controller
public class TitleEstimateController : ApiController
{
public class EstimateQuery
{
public string username { get; set; }
}
public IHttpActionResult GetTitleEstimate([FromUri] EstimateQuery query)
{
// All the values in "query" are null or zero
// Do some stuff with query if there were anything to do
if(query != null && query.username != null)
{
return Ok(query.username);
}
else
{
return Ok("Add a username!");
}
}
}
You can read more details about WebApi routing here. From reading it you can probably come up with an alternative solution within your route config. There are also lots of terrific examples in this blog post.
First, I would try to use the attribute routing feature of web.api like this:
[RoutePrefix("api/titleestimate")]
public class TitleEstimateController : ApiController
{
[HttpGet]
public IHttpActionResult GetTitleEstimate([FromUri] EstimateQuery query)
{
// All the values in "query" are null or zero
// Do some stuff with query if there were anything to do
}
}
It would also be helpful to see the request in your dev tools. I disagree with Colin that you should make this a POST, because HTTP POST is supposed to be used to create new items. You are trying to get information so HTTP GET makes sense.
I think Web.Api assumes methods are GETs by default, but declarating it with the HttpGet attribute will for sure take care of that.
For complex objects, I usually send them in the message body rather than the URL.
Would you have any objection to an approach similar to the answer of this question?
How to pass json POST data to Web API method as object
It seems like the more straightforward/natural approach.
Something like (untested, but should be close):
[RoutePrefix("api/titleestimate")]
public class TitleEstimateController : ApiController
{
[HttpGet]
public IHttpActionResult GetTitleEstimate([FromBody] EstimateQuery query)
{
// All the values in "query" are null or zero
// Do some stuff with query if there were anything to do
}
}
public class EstimateQuery
{
public string QueryName{ get; set; }
public string Whatever{ get; set; }
}
$(function () {
var query = {QueryName:"My Query",Whatever:"Blah"};
$.ajax({
type: "GET",
data :JSON.stringify(query),
url: "api/titleEstimate",
contentType: "application/json"
})
.done(function (data) {
$('#product').text("OK");
})
.fail(function (jqXHR, textStatus, err) {
$('#product').text('Error: ' + err);
});
});