Greetings I have a WCF service, and basically what the API users do to create a book is following:
var Book = new DtoBook()
{
OpenInModal = false,
CallToActionUrl = "url"
Status = NotificationStatus.Unseen,
TimeStamp = DateTime.Now,
Type = NotificationType.Type,
Message = "test,
};
BookManager.Instance.Add(Book);
I have users to basically do the same thing but instead on the client-side.
I have created a POST method already that looks like this:
public HttpResponseMessage Add(List<DtoBook> Books)
{
if (!ModelState.IsValid)
{
return Request.CreateResponse(HttpStatusCode.BadRequest);
}
BookManager.Instance.Add(Books);
var response = Request.CreateResponse(HttpStatusCode.Created, Books);
return response;
}
So when I enter the url I get following in my console:
{"Message":"The request is invalid.","MessageDetail":"The parameters dictionary contains a null entry for parameter 'id' of non-nullable type 'System.Int32' for method 'System.String Get(Int32)' in 'test.Controllers.NotificationsController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter."}
My question is what do I need to do so the user can type the properties of the dToBook class and then the POST happens and the book gets added. I guess right now it just tries to add it without any properties.
Any kind of help is appreciated
Try to specify the method is post, for sample:
[HttpPost]
public HttpResponseMessage Add([FromBody]List<DtoBook> Books)
{
// code
}
Related
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"
}
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);
}
I'm trying to implement some post functionality in my app.
I have got the following post method:
restrictLoginAttemptsFromSingleIp: function (id, userId) {
var serviceUri = baseServicesUrlService.getBaseServicesUrl() + "/employee-service/restrict-single-ip";
return $http.post(serviceUri, {restrictLoginAttemptIp: {loginAttemptIds: [id]}, dataOwnerId: userId});
}
My server side is using RESTEasy 3.0.4 with Hibernate validation:
#POST
#Path("/restrict-single-ip")
public Response RestrictSingleIp(#Valid RestrictLoginAttemptIpRequest requestData, #Context HttpRequest request){
return Response.status(200).build();
}
The RestrictLoginAttemptIpRequest class inherits one field (dataOwnerId) of type Long from PostBase:
public class RestrictLoginAttemptIpRequest extends PostBase {
private RestrictLoginAttemptIp restrictLoginAttemptIp;
public RestrictLoginAttemptIp getRestrictLoginAttemptIp() {
return restrictLoginAttemptIp;
}
public void setRestrictLoginAttemptIp(RestrictLoginAttemptIp restrictLoginAttemptIp) {
this.restrictLoginAttemptIp = restrictLoginAttemptIp;
}
}
The RestrictLoginAttemptIp class:
package blah;
import org.hibernate.validator.constraints.NotEmpty;
import java.util.List;
public class RestrictLoginAttemptIp {
#NotEmpty(message = "blah")
private List<Long> loginAttemptIds;
public List<Long> getLoginAttemptIds() {
return loginAttemptIds;
}
public void setLoginAttemptIds(List<Long> loginAttemptIds) {
this.loginAttemptIds = loginAttemptIds;
}
}
I get the following data string from the POST request which seems to be ok:
{restrictLoginAttemptIp={loginAttemptIds=[328]}, dataOwnerId=8}
Can someone please explain me why I get an 400 Bad request error when I invoke that function?
Is this because of Long datatypes? Should I somehow mark them in Javascript to be Longs?
Ok after 4 hours I figured out the problem.
The case is, that I'm reading the POST data (solving permission questions) in a security interceptor. Reading POST data in RESTEasy is a little bit tricky. To create a LinkedHashMap I use Apache IOUtils (https://commons.apache.org/proper/commons-io/javadocs/api-release/org/apache/commons/io/IOUtils.html) like it is figured out in the next code snippet
String result = IOUtils.toString(requestContext.getEntityStream());
ObjectMapper mapper = new ObjectMapper();
Object obj = mapper.readValue(result, Object.class);
I looked up in my AngularJS interceptor (used for example for putting something in the header of every request) and figured out, that the server cannot read the input stream: java.io.ioexception no content to map to object due to end of input.
At the end the problem was, that after I once read the EntityStream of the ContainerRequestContext it became empty. The solution was to repopulate it after reading POST data. Something like this:
private LinkedHashMap getPostData(ContainerRequestContext requestContext) {
Object obj = null;
try {
String result = IOUtils.toString(requestContext.getEntityStream());
ObjectMapper mapper = new ObjectMapper();
obj = mapper.readValue(result, Object.class);
//IMPORTANT: After you can get the entity stream only once. After reading the entity stream is empty
//so the JSON parser cannot convert EMPTY entity stream into any object. To avoid strange errors (like 400 Bad Request)
//you have to convert the string back to input stream and rewrite the empty entity stream.
InputStream stream = IOUtils.toInputStream(result);
requestContext.setEntityStream(stream);
System.out.println(obj);
} catch (IOException e) {
e.printStackTrace();
}
return (LinkedHashMap) obj;
}
P. S. ObjectMapper comes from Jackson
For various reasons, I have switched from ASP.NET MVC's built in JSON serializer (the one that returns a System.Web.Mvc.JsonResult object (see edit below)) to Newtonsoft. I didn't realize until after I began testing that the former returns a JavaScript object literal, while Newtonsoft returns a JSON formatted string.
I like not having to parse JSON strings on the client side — having it already as an object literal is very convenient — but I want to stick with Newtonsoft for other technical reasons.
For example, instead of seeing this result on my client...
"{"Errors":["Please enter a valid email address."],"HasErrors":true}"
...I'd like to see this result:
{"Errors":["Please enter a valid email address."],"HasErrors":true} // no quotes
Is there a way to make Newtonsoft return JS object literals instead of strings?
EDIT
The way my question was framed wasn't the best. There's nothing wrong with the JsonResult type. In fact, the solution still uses it. The only problem was the default Controller.Json methods, which can be overridden to use Newtonsoft (Json.NET) instead of the built-in serializer.
Just write a custom JsonResult that uses Newtonsoft serializer:
Something along the lines:
public abstract class BaseController : Controller
{
protected override JsonResult Json(object data, string contentType, System.Text.Encoding contentEncoding)
{
return new JsonNetResult
{
ContentType = contentType,
ContentEncoding = contentEncoding,
Data = data
};
}
protected override JsonResult Json(object data, string contentType, System.Text.Encoding contentEncoding, JsonRequestBehavior behavior)
{
return new JsonNetResult
{
ContentType = contentType,
ContentEncoding = contentEncoding,
Data = data,
JsonRequestBehavior = behavior
};
}
}
JsonNetResult.cs:
using System;
using System.Web;
using System.Web.Mvc;
using Newtonsoft.Json;
public class JsonNetResult : JsonResult
{
public JsonSerializerSettings SerializerSettings { get; set; }
public Formatting Formatting { get; set; }
public JsonNetResult()
{
Formatting = Formatting.None;
SerializerSettings = new JsonSerializerSettings();
JsonRequestBehavior = JsonRequestBehavior.DenyGet;
}
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
throw new ArgumentNullException("context");
if (JsonRequestBehavior == JsonRequestBehavior.DenyGet
&& String.Equals(context.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))
{
throw new InvalidOperationException("This request has been blocked because sensitive information could be disclosed to third party web sites when this is used in a GET request. To allow GET requests, set JsonRequestBehavior to AllowGet.");
}
HttpResponseBase response = context.HttpContext.Response;
response.ContentType = !string.IsNullOrEmpty(ContentType)
? ContentType
: "application/json";
if (ContentEncoding != null)
response.ContentEncoding = ContentEncoding;
if (Data != null)
{
var writer = new JsonTextWriter(response.Output) { Formatting = Formatting };
var serializer = JsonSerializer.Create(SerializerSettings);
serializer.Serialize(writer, Data);
writer.Flush();
}
}
}
Credit: https://gist.github.com/jpoehls/1424538
Answer is here: How to force ASP.NET Web API to always return JSON?
Excerpt:
Clear all formatters and add Json formatter back.
GlobalConfiguration.Configuration.Formatters.Clear();
GlobalConfiguration.Configuration.Formatters.Add(new JsonMediaTypeFormatter());
EDIT
I added it to Global.asax inside Application_Start().
that's my function:
<script> function Calculate()
{
var ItemPrice = document.getElementById("price");
var weight = document.getElementById("weight");
var SelWeight = weight.options[weight.selectedIndex].value;
alert(SelWeight);
var Category = document.getElementById("SelectedCategory");
var SelCategory = Category.options[Category.selectedIndex].value;
alert(SelCategory);
}
</script>
i want to get SelCategories.Tax and SelCategories.Duty to add them to weight value and total price to show the total in a label.. I'm using ASP.NET MVC 4 and this is my Model that i want to use
public class CategoriesModel
{
public int CategoryID { get; set; }
public string CategoryName { get; set; }
public decimal Duty { get; set; }
public decimal Tax { get; set; }
public IEnumerable<SelectListItem> CategoriesList { get; set; }
}
I think the best approach here is to use Json and something like Vue.js, Knockout.js, etc. (but also you can do it without these libraries, if your case is simple).
First, you need to install Json support with a command in PM console:
PM> install-package NewtonSoft.Json
Then, in your view you can convert your model to javascript object like this:
#model ...
#using Newtonsoft.Json
...
<script type="text/javascript">
var data = #Html.Raw(JsonConvert.SerializeObject(this.Model));
</script>
Then you can access all the properties in your model with in plain JavaScript:
var id = data.CategoryID;
That's it! Use knockout (update 2018: this is obsolete, there is no reason you should use knockout now) if your logic is complicated and you want to make your view more powerful. It could be a little bit confusing for newbie, but when you get it, you'll gain the super-powerful knowledge and will be able to simplify your view code significantly.
You need to create actions (methods in the controller) that return JsonResult.
From the client side, make ajax calls to the server to recover and use that data. The easiest way to do this is to use any of the jQuery ajax methods.
public JsonResult GetData(int id)
{
// This returned data is a sample. You should get it using some logic
// This can be an object or an anonymous object like this:
var returnedData = new
{
id,
age = 23,
name = "John Smith"
};
return Json(returnedData, JsonRequestBehavior.AllowGet);
}
When you use a jQuery get to the /ControllerName/GetData/id, you'll get a JavaScript object in the success callback that can be used in the browser. This JavaScript object will have exactly the same properties that you defined in the server side.
For example:
function getAjaxData(id) {
var data = { id: id };
$.get('/Extras/GetData/1', // url
data, // parameters for action
function (response) { // success callback
// response has the same properties as the server returnedObject
alert(JSON.stringify(response));
},
'json' // dataType
);
}
Of course, in the success callback, instead of making an alert, just use the response object, for example
if (response.age < 18) { ... };
Note that the age property defined in the server can be used in the JavaScript response.
If you prefer a class try jsmodel. After converting the mvc view model to javascript it adds the benefit of retrieving DOM updates.
var jsmodel = new JSModel(#Html.Raw(Json.Encode(Model)));
Then anytime you want to get the latest state of the DOM do this to update your variable:
var model = jsmodel.refresh();
Website:
http://chadkuehn.com/jquery-viewmodel-object-with-current-values/
There is also a nuget:
https://www.nuget.org/packages/jsmodel/
var errors = '#Html.Raw(Json.Encode(ViewData.ModelState.Values.SelectMany(v => v.Errors).Select(e => e.ErrorMessage)))';
var errorMessage=JSON.parse(errors);