ASP.NET WEB API Not able to retrieve Post Parameters - asp.net

I trying to retrieve post parameters in web API but I do get null values everytime.
My html
<form method="POST" action="http://localhost:16192/update" name="myform">
<input name="title" type="text"/>
<input name="isbn" type="text"/>
<input name="author" type="text"/>
<input type="submit" value="Submit"/>
</form>
And My WebAPI
[HttpPost]
[Route("UPDATE/")]
public String updateRecord([FromBody]String title,String isbn="", String author="")
{
return "Updated";
}
The updateRecord method is being called but I always get null values. Any help would be greatly appreciated.

[HttpPost]
[Route("UPDATE/")]
public String updateRecord([FromBody]dynamic values)
{
var title = values.title.Value;
....
return "Updated";
}
or you can create a DTO object (paragraph 2):
http://encosia.com/using-jquery-to-post-frombody-parameters-to-web-api/

Related

Saving record in a proper way

I have a problem with saving records to DB with Spring-Mvc and Thymeleaf.
When I click "Update" button on record, to enter the update form (included beneath), all values are in place correctly, but, when I want to subbmit, an error occur. There is no any stacktrace in console, only error in web page, that I am not able to solve.
This is my code:
Controller:
#GetMapping("/{maltId}")
public ModelAndView showMalt(#PathVariable("maltId") Long maltId) {
ModelAndView mav = new ModelAndView("malt/malt-show");
mav.addObject(maltService.findById(maltId));
return mav;
}
#GetMapping("/{maltId}/edit")
public String initUpdateMaltForm(#PathVariable("maltId") Long maltId, Model model) {
model.addAttribute("malt", maltService.findById(maltId));
return VIEWS_MALT_CREATE_OR_UPDATE_FORM;
}
#PostMapping("/{maltId}/edit")
public String processUpdateMaltForm(#Valid Malt malt, BindingResult result, #PathVariable("maltId") Long maltId) {
if (result.hasErrors()) {
return VIEWS_MALT_CREATE_OR_UPDATE_FORM;
} else {
malt.setId(maltId);
Malt savedMalt = maltService.save(malt);
return "redirect:/malt/" + savedMalt.getId();
}
}
Model:
#Column(name="malt_name")
private String maltName;
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="producer_id")
private Producer producer;
#Column(name="malt_filling")
private int maltFilling;
#Column(name="malt_ebc")
private int maltEbc;
#Column(name="malt_usage")
private String maltUsage;
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="country_id")
private Country country;
#ManyToMany(mappedBy="malts")
private Set<Batch> batches;
This is the view:
<body>
<form th:object="${malt}" th:action="#{/malt/}" method="post">
<input type="hidden" th:field="*{id}" />
<label>Malt name:</label>
<input type="text" class="form-control" th:field="*{maltName}" />
<label>Producer:</label>
<input type="text" class="form-control"
th:field="*{producer.producerName}" />
<label>Country:</label>
<select class="form-control" th:field="*{country.id}">
<option value="0">Select country</option>
<option th:each="country : ${countries}"
th:value="${country?.id}"
th:text="${country?.countryName}">
</option>
</select>
<label>Malt filling:</label>
<input type="text" class="form-control"
th:field="*{maltFilling}" />
<label>Malt usage:</label>
<input type="text" class="form-control"
th:field="*{maltUsage}" />
<label>Malt EBC:</label>
<input type="number" class="form-control"
th:field="*{maltEbc}" />
<button class="submit-button" type="submit">Submit</button>
</form>
</body>
When I hit Submit button, I get this error:
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Wed May 15 22:46:22 CEST 2019
There was an unexpected error (type=Not Found, status=404).
No message available
I have tried couple of different approaches, but nothing helps, and since there is no stacktrace in console, I have no idea what is wrong here.
Link to repo: https://github.com/fangirsan/maruszka-new
No stack trace 404 normally indicates that there is no mapping. Since you have, potentially, provided only a part of your Controller I assume that the causation for this is the code in your view right here:
<form th:object="${malt}" th:action="#{/malt/}" method="post">
The action takes to ("/malt/"), however, your controller has not got mapping for this?!
I expect that this should fix it:
<form th:object="${malt}" th:action="#{${'/' + malt.id + '/edit'}}" method="post">
Update
Had a look at your controller and you have the following annotations on your class
#Controller
#RequestMapping("/malt")
public class MaltController{..
#RequestMapping("/malt") will now make your path to save ../malt/{id}/edit'. The code below now should work:
<form th:object="${malt}" th:action="#{${'/malt/' + malt.id + '/edit'}}" method="post">
On using "#{${...}}"
#{} is a link variable, contents within this tag will be appended to the applications root context, e.g., at Stack Overflow #{'/posts'} would result with https://stackoverflow.com/posts
The ${} is a variable expression which will return a String or the object's .toString() value.
If we want to pass a variable within #{} link variable we must include the ${} variable within it, thus resulting in :
#{${'/hope/this/helps' + yourVariable}}

how to get data from a form("multipart/form-data") with springMvc?

how to get data from a form("multipart/form-data") with springMvc?
i want to upload a file(a photo),so the type of form is 'multipart/form-data'
but i found that springMVC cannot map data(in the form) into the property of User,I know i should use multipartFile to accept the picture,but how can other data in the form be mapped into object User automatically ?
<form enctype="multipart/form-data" type="post" action="....">
<input type"file" name="photo"/>
<input type"text" name="username"/>
.....
</form>
#RequestMapping("...")
public String editUser(User user,MultipartFile multipartFile){
.....
}
I get a 400 bad request error,so does anyone know how to achieve it? thanks a lot if someone help me out
You can do like this:-
<form enctype="multipart/form-data" type="post" action="....">
<input type"file" name="photo"/>
<input type"text" name="username"/>
.....
</form>
add model attribute on this page and use it in
your controller like this:-
#RequestMapping("...")
public String editUser(#RequestParam("photo") MultipartFile photo,
#ModelAttribute("your model attribute") User user){
.....
}

How to use input radio button with thymeleaf and Spring MVC

I would like to get a destination address from a input radio button list. The DestinationAddress class is the following:
public class DestinationAddress {
private Integer destinationAddressId;
private String name;
private Location location;
private User owner;
public DestinationAddress(String name, Location location, User owner) {
this.name = name;
this.location = location;
this.owner = owner;
}
public DestinationAddress() {
}
// getter and setter
}
The controller who handles the get and post is the following:
#PreAuthorize("hasRole('USER')")
#GetMapping(value = "/select-address")
public String selectAddress(Principal principal, Model model) {
List<DestinationAddress> addresses = destinationAddressService.getAllByUsername(principal.getName());
model.addAttribute("destinationAddresses", addresses);
model.addAttribute("destinationAddress", new DestinationAddress());
return "purchase/select-address";
}
#PreAuthorize("hasRole('USER')")
#PostMapping(value = "/select-address")
public String selectAddress(#ModelAttribute DestinationAddress destinationAddress, Principal principal) {
Purchase purchase = purchaseService.addPurchase(principal.getName(), destinationAddress);
return "redirect:/purchases/pay/" + purchase.getPurchaseId();
}
And the html page is the following:
<form th:object="${destinationAddress}" method="post">
<fieldset>
<legend>Your addresses</legend>
<ul>
<li th:each="destinationAddress : ${destinationAddresses}">
<input type="radio" th:field="*{destinationAddressId}" th:value="${destinationAddress.destinationAddressId}" />
<label th:for="${#ids.prev('destinationAddress.destinationAddressId')}" th:text="${destinationAddress}"></label>
</li>
</ul>
</fieldset>
<p><input type="submit" value="Submit" /> <input type="reset" value="Reset" /></p>
</form>
The error message is the following:
java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'destinationAddressId' available as request attribute
I don't know what's the problem here. I don't know which type will the form return to the controller. So I don't know which variable pass to the model and which one to get from the post controller method. Integer or DestinationAddress? I cannot find anything googling it, just small pieces of code without any explanations. Any suggestions?
I found a solution to my problem. I changed the html page, now it looks like this:
<form th:object="${address}" method="post">
<fieldset>
<legend>Your addresses</legend>
<ul>
<li th:each="destinationAddress : ${destinationAddresses}">
<input type="radio" th:field="${address.destinationAddressId}" th:value="${destinationAddress.destinationAddressId}" />
<label th:for="${destinationAddress.destinationAddressId}" th:text="${destinationAddress}"></label>
</li>
</ul>
</fieldset>
<p><input type="submit" value="Submit" /> <input type="reset" value="Reset" /></p>
</form>
I changed the name of the object inside the model because it was the same as the name of the temp destinationAddress of the loop. I also replaced '{#ids.prev(' because it was giving me an error:
Cannot obtain previous ID count for ID ...
Now it works fine.

Handling map-like request parameters in Spring MVC

Say I have a form for a list of questions where I need a 0/1 answer. I could easily model a static list with radios, something like
<input type="radio" name="question1" value="0">
<input type="radio" name="question1" value="1">
<br>
<input type="radio" name="question2" value="0">
<input type="radio" name="question2" value="1">
#RequestMapping("/answer")
public String answer(Integer question1, Integer question2) {
But I have a dynamic list of questions instead, where each question has a numeric ID. I therefore tried to model it like the following (the HTML is dynamically created with an iteration on the question list):
<input type="radio" name="question[42]" value="0">
<input type="radio" name="question[42]" value="1">
<br>
<input type="radio" name="question[51]" value="0">
<input type="radio" name="question[51]" value="1">
where 42 and 51 are the question id.
I was expecting to capture all values in a Map parameter of my Spring controller, like so:
#RequestMapping("/answer")
public String answer(#RequestAttribute("question") HashMap<Integer, Integer> question) {
It didn't work (the method isn't called).
I also tried with string ids:
<input type="radio" name="question['42']" value="0">
#RequestMapping("/answer")
public String answer(#RequestAttribute("question") HashMap<String, Integer> question) {
Same as before.
It only works if I use a map of string/string, but in this case I get all request parameters in the map, which I will then need to parse:
#RequestMapping("/answer")
public String answer(#RequestAttribute("question") HashMap<String, String> question) {
--> question.keys: "question[42]", "question[51]"
So what is the proper way of handling dynamic radios, or more generally map-like request parameters?
I don't know why, but it works if I put the map inside a bean:
public class QuestionForm {
private HashMap<Long, String> question;
public HashMap<Long, String> getQuestion() {
return question;
}
public void setQuestion(HashMap<Long, String> question) {
this.question = question;
}
}
#RequestMapping("/answer")
public String answer(QuestionForm questionForm) {

On Form POST values are displayed in URL

Controller's Action1 calls a view which contains the following HTML code:
#using(Html.BeginForm("Action2","Controller",new {ID = ViewBag.Link},FormMethod.Post,new {#class =""}))
{
#Html.AntiForgeryToken()
<input type="submit" value= "Submit"/>
}
When the user Submits this Form following method is called:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Action2(int ID)
{
//Something
return View("Display");
}
When this "Display" view is displayed the URL contains: //Controller/Action2?ID=1
How to avoid this values from being visible in the URL even after the FormMethod is POST?
It is happening because you're sending the ID as a route value. If you want it to stay out of the URL, instead send it via a hidden input element
#using(Html.BeginForm("Action2"))
{
#Html.AntiForgeryToken()
<input type="hidden" name="ID" value="#ViewBag.Link" />
<input type="submit" value= "Submit"/>
}

Resources