JObject parameter is null in WebApi Action - asp.net-web-api

I have an api controller action that takes a JObject as a
public class ThemeController : ApiController
{
[HttpGet]
public String Get(String siteName, JObject lessVariables)
{
and an ajax call
$.ajax({
url: '/api/Theme/Get',
data: { lessVariables: JSON.stringify({'brand-primary': '#222222','brand-success': '#222222','brand-danger': '#222222','brand-info': '#222222','btn-primary-color': '#222222'}), siteName: "UnivOfUtah" }
});
When I look at HttpContext.Current.Request.Params["lessVariables"] it gives the correct string of json, but lessVariables is an empty JObject. Is there something else I have to do to setup Json.Net for this?
I've also tried it on a regular controller action
I have a controller action that takes a JObject as a
public class ThemeController : Controller
{
[HttpPost]
public String Post(String siteName, JObject lessVariables)
{
and an ajax call
$.ajax({
url: '/Theme/Post',
data: { lessVariables: JSON.stringify({'brand-primary': '#222222','brand-success': '#222222','brand-danger': '#222222','brand-info': '#222222','btn-primary-color': '#222222'}), siteName: "UnivOfUtah" }
});
same result

The problem is that lessVariables is now a String. The whole structure probably looks like:
{
"lessVariables": "{'brand-primary': '#222222','brand-success': '#222222','brand-danger': '#222222','brand-info': '#222222','btn-primary-color': '#222222'}",
"siteName": "UnivOfUtah"
}
This is why you can see the correct string in the Params, but the framework is not able to convert it to JObject without knowing it is Json. When you Stringify the root object of a request, WebApi is smart enough to take it as Json as a whole, but you stringified a value inside so it has no idea it should be handled as json.
To fix it, you can either do custom binding with a model binder or custom action, or simply change your method to:
[HttpGet]
public String Get(String siteName, String lessVariables)
{
JObject jo = JObject.Parse(lessVariables);
Update:
To make the issue clearer, this is parsed fine by WebApi, but lessVariables is still a string:
[HttpGet]
public String Get(JObject rootObject)
{
// you now have rootObject which has a "siteName" and "lessVariables" parameter
var siteName = rootObject.GetValue("siteName");
var lessVariables = rootObject.GetValue("lessVariables");
// lessVariables.Type would return the JTokenType String

Related

asp.net web api controller method taking special parameter

I have an api that takes 2 parameters by querystring :
We call it like this :
mydomain/myapimethod?url=www.toto.com&caller=tata
We receive parameters like this :
[HttpGet]
[Route("myapimethod")]
public HttpResponseMessage Get([FromUri] string url, [FromUri] string caller)
{
//here url: www.toto.com and caller: tata
}
Everything is working well, the problem is when the url parameter is also composed of querystring with several parameters, for example :
mydomain/myapimethod?url=www.toto.com?parama=a&paramb=b&caller=tata
Then in my method :
[HttpGet]
[Route("myapimethod")]
public HttpResponseMessage Get([FromUri] string url, [FromUri] string caller)
{
//here url: www.toto.com?parama=a and caller: tata
// my paramb is removed
// what I would like to do is to obtain :
// url: www.toto.com?parama=a&paramb and caller: tata
}
My url is generatated by javascript.
You must update your url from
mydomain/myapimethod?url=www.toto.com?parama=a&paramb=b&caller=tata
to
mydomain/myapimethod?url=www.toto.com&parama=a&paramb=b&caller=tata
or encode question mark to %3F
mydomain/myapimethod?url=www.toto.com%3Fparama=a&paramb=b&caller=tata

How to show model attribute in JSP after using ajax?

I have a problem. I pass index value from JSP to controller successfully with ajax. When I click 'pass' button, the 'index' value is increasing and it passes to controller successfully with ajax. According to this index, I add list[index] to model.(with model.addAttribute) Although I have used ${nextWord} in the JSP, I cannot see this value in the view. How can I fix it? Thanks for your answer.
Controller
private List<Map<String, Object>> list;
#RequestMapping(value="/practice/{category}", method = RequestMethod.GET)
public String practicePageStart(#PathVariable("category") String category,
ModelMap model, HttpSession session){
// return 10 value from DB. Example;
// [{idWord=1},{word='exampleWord'},{meaning='turkishMeaning'},{type='NOUN'}]
list = wordService.getRandomWords(Integer.parseInt(String.valueOf(session.getAttribute("wordCount"))));
model.addAttribute("wordList", list);
return "practiceCategory";
}
#RequestMapping(value="/practice/{category}", method = RequestMethod.POST)
public String practicePagePost(#PathVariable("category") String category,
#RequestParam("index") int index, ModelMap model, HttpSession session){
model.addAttribute("nextWord", list.get(index).get("word"));
return "practiceCategory";
}
JSP
<script>
$(document).ready(function() {
$('#pass').click(function(event) {
var inputIndex = $('#index').val();
$.ajax({
type: "POST",
url: "${pageContext.request.contextPath}/practice/${category}",
async: false,
data: { index: inputIndex }
complete: function(){
alert("${nextWord}");
$('#label').text("${nextWord}");
}
});
document.getElementById("index").value = (parseInt(document.getElementById("index").value) + 1).toString();
});
});
</script>
Change your controller method to this:
#RequestMapping(value="/practice/{category}", method = RequestMethod.POST)
#ResponseBody
public String practicePagePost(#PathVariable("category") String category,
#RequestParam("index") int index, ModelMap model, HttpSession session){
return list.get(index).get("word");
}
And your ajax to this:
$.ajax({
type: "POST",
url: "${pageContext.request.contextPath}/practice/${category}",
async: false,
data: { index: inputIndex }
success: function(data){
alert(data);
$('#label').text(data);
}
});
Use #ResponseBody and return the object rather then returning a ViewResolver.
Returning a ViewResolver will resolve the view and send the html content while doing an Ajax call. Hence, it is not recommended if u need only value.
#ResponseBody example
public #ResponseBody Integer retriveValue(-,-,-){
return Integer.valueOf(5);
}
In my opinion you mix different:
(1) rendring phase (servlet container - background - java) vs.
(2) running in browser (js, no request attribute existing here).
You need one another jsp file just for rendering the data. Or you return it as json in practicePagePost method.
#ResponseBody
#RequestMapping(value="/practice/{category}", method = RequestMethod.POST)
public String practicePagePost(#PathVariable("category") String category,
#RequestParam("index") int index, ModelMap model, HttpSession session){
return list.get(index).get("word");
}

How to map Bootstrap Modal to Spring MVC controller

I have a form in Bootstrap Modal and I want my Spring MVC controller to listen that. My problem is that the modal doesn't generate href because it's inside current page so I can't map just the modal in my Spring MVC controller.
I need it, because I want to show errors from bindingresult object. How can I do this?
This is my modal: http://www.bootply.com/zerZIYpNAF Let's say it's located in index.jsp so imaginary path would be /index#myModal.jsp or something like that.
#RequestMapping(value="/send", method = RequestMethod.GET)
public String get(Dummybean bean){
return "??"; //index#myModal
}
#RequestMapping(value="/send", method = RequestMethod.POST)
public String post(#Valid #ModelAttribute("dummy") DummyBean bean, BindingResult bindingResult){
if(bindingResult.hasErrors()){
return "??"; //index#myModal
}
//do something
}
public class DummyBean{
#NotNull
private String name;
public String getName() {
return username;
}
public void setName(String name) {
this.name = name;
}
You can't directly call the bootstrap modal to pop up by using controller. There for you will not able to bind form with Spring. But you can Achieve it using Ajax. You have to use form like normal Html form without using spring tags.
function searchAjax() {
var data = {}
data["query"] = $("#query").val();
$.ajax({
type : "POST",
contentType : "application/json",
url : "${home}search/api/getSearchResult",
data : JSON.stringify(data),
dataType : 'json',
timeout : 100000,
success : function(data) {
console.log("SUCCESS: ", data);
display(data);
},
error : function(e) {
console.log("ERROR: ", e);
display(e);
},
done : function(e) {
console.log("DONE");
}
});
}
This is an example ajax for you to get an idea. You have to HttpServletRequest to retrieve data from controller side. Above example is taken from http://www.mkyong.com/spring-mvc/spring-4-mvc-ajax-hello-world-example/
1) create new function just for validation
2) create js function using prefer to use jquery and send ajax request to function in step one.
3) depend on validation status will handle errors or send form completely.
please read this article it's fully answered your question
javacodegeeks.com

Posting to Web Api parameters are null

I have a jquery method which looks like this:
$.post("/api/amazon/signature", { "policy": policy }, function (data) {
console.log(data);
});
the api method looks like this~:
// POST api/amazon/signature
[HttpPost]
[Route("api/amazon/signature")]
public IHttpActionResult GetSignature([FromBody]string policy)
{
var bKey = Encoding.ASCII.GetBytes(ConfigurationManager.AppSettings["AWSSecretKey"]);
var hmacSha1 = new HMACSHA1(bKey);
var bPolicy = Encoding.ASCII.GetBytes(policy);
var hash = hmacSha1.ComputeHash(bPolicy);
var encoded = Convert.ToBase64String(hash);
return Ok(encoded);
}
but when I run this code policy is always null!
If I change my method to this:
public class Signature
{
public string Policy { get; set; }
}
// POST api/amazon/signature
[HttpPost]
[Route("api/amazon/signature")]
public IHttpActionResult GetSignature([FromBody]Signature model)
{
var bKey = Encoding.ASCII.GetBytes(ConfigurationManager.AppSettings["AWSSecretKey"]);
var hmacSha1 = new HMACSHA1(bKey);
var bPolicy = Encoding.ASCII.GetBytes(model.Policy);
var hash = hmacSha1.ComputeHash(bPolicy);
var encoded = Convert.ToBase64String(hash);
return Ok(encoded);
}
and modify my jquery to this:
$.post("/api/amazon/signature", { "Policy": policy }, function (data) {
console.log(data);
});
it works fine....
Can someone tell me why?
ASP.NET Web API binds the request body in its entirety to one parameter (one parameter only and not more). By default, body is bound to a complex type. So, when you change the parameter type to Policy which is a complex type, you don't need to actually specify FromBody. Also binding works correctly now because you are sending JSON Object which looks something like this { "policy": policy }. Web API has no trouble in binding JSON object to your complex type.
When it comes to a simple type, string in your case, you must specify FromBody, since by default Web API binds from URI path and query string. In that case however, you cannot send a JSON Object. Web API is going to bind the entire body to that parameter, which is string. So, the request body must be just a string like this - "ABC123" and not a JSON object. If you send just "ABC123" (including the quotes) in the request body, your string parameter will be populated with ABC123.

How To Pass formdata parameters into ASP.NET WebAPI without creating a record structure

I have data coming into my form that looks like the image below (sessionsId: 1367,1368).
I've create c# in my webapi controller that works as below. when I've tried ot just make use SessionIds as the parameter (or sessionIds) by saying something like PostChargeForSessions(string SessionIds) either null gets passed in or I get a 404.
What is the proper way to catch a form parameter like in my request without declaring a structure.
(the code below works, but I'm not happy with it)
public class ChargeForSessionRec
{
public string SessionIds { get; set; }
}
[HttpPost]
[ActionName("ChargeForSessions")]
public HttpResponseMessage PostChargeForSessions(ChargeForSessionRec rec)
{
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK, new ShirtSizeReturn()
{
Success = true,
//Data = shirtSizeRecs
});
return response;
}
You can declare the action method like this.
public HttpResponseMessage Post(string[] sessionIds) { }
If you don't want to define a class, the above code is the way to go. Having said that, the above code will not work with the request body you have. It must be like this.
=1381&=1380

Resources