How request works in Play Framework 2? - json

I've got to say I'm a little confused about how to handle request parameter using the new Play Framework 2. The data comes from different origins regarding how the request is made. So far, here's the possibilities :
1 - If you do a simple GET :
ctx().request().queryString()
2 - If you do a POST using an HTML Form :
The form :
<form method="post" action="/">
<input type="hidden" name="foo" value="bar" />
<input type="hidden" name="t" value="1" />
<input type="hidden" name="bool" value="true" />
<input type="submit" name="submit" value="Submit" />
</form>
The method :
public static Result test() {
ctx().request().queryString(); // {} ; As expected
ctx().request().body(); // contains data
ctx().request().body().asFormUrlEncoded(); // contains data
ctx().request().body().asJson(); // empty
return ok();
}
This seems normal.
Now if I add #BodyParser.Of(BodyParser.Json.class) (suppose I accept both Ajax POST and normal POST for fallback in Non-JS case) :
#BodyParser.Of(BodyParser.Json.class)
public static Result test() {
ctx().request().queryString(); // {} ; as Expected
ctx().request().body(); // contains data
ctx().request().body().asFormUrlEncoded(); // empty : Shouldn't this contains data since I posted them via a simple form ?!
ctx().request().body().asJson(); // empty
return ok();
}
And then, the hell hapened : How can I get the values of a simple form if none of them are filled (asJson, asFormUrlEncoded, etc) ?!
3 - If you do a POST via AJAX :
// Code in JS used :
$.ajax({
'url': '/',
'dataType': 'json',
'type': 'POST',
'data': {'foo': 'bar', 't': 1, 'bool': true}
});
Result :
public static Result test() {
ctx().request().queryString(); // {}
ctx().request().body(); // contains data
ctx().request().body().asFormUrlEncoded(); // contains data
ctx().request().body().asJson(); // empty
return ok();
}
With the #BodyParser.Of(BodyParser.Json.class) :
#BodyParser.Of(BodyParser.Json.class)
public static Result test() {
ctx().request().queryString(); // {}
ctx().request().body(); // contains data
ctx().request().body().asFormUrlEncoded(); // empty
ctx().request().body().asJson(); // empty : Shouldn't this contains data since I espect JSON ?!
return ok();
}
Here the inconsistencies is the asJson() method that should return the data since, according to the doc
Note: This way, a 400 HTTP response will be automatically returned for non JSON requests. (http://www.playframework.org/documentation/2.0/JavaJsonRequests)
What I'd like to know is what is the best decorator+method for a POST that would accept a simple post from HTML or an Ajax Request with POST?

I would recommend to use the Form classes provided by PlayFramework.
The Form will bind its values to the provided request data.
There are two different Form implementations:
DynamicForm: POST data is available through Map accessors methods
Form: the generic form of Form will map the POST data to an instance of an entity class [more information]
The form also provides some usefull features like automatic type conversion, validation, error reporting and so on.
a simple example with a dynamic form:
ajax request:
$.post("#routes.Application.movetodo()",
{ "id": 123, "destination": destination }, function(data)
{
// do something when request was successfull
});
Routes file:
GET / controllers.Application.index()
POST /movetodo controllers.Application.movetodo()
Controller implementation:
public static Result movetodo()
{
DynamicForm data = form().bindFromRequest(); // will read each parameter from post and provide their values through map accessor methods
// accessing a not defined parameter will result in null
String id = data.get("id");
String destination = data.get("destination");
return ok();
}

The reason that asJson() will be empty is that by default, $.ajax will send a request with a content type set to 'application/x-www-form-urlencoded; charset=UTF-8'. You need to set it to 'application/json; charset=utf-8':
$.ajax({
contentType: "application/json; charset=utf-8",
...
})

Related

MVC - returning data via ajax call renders it as page

New to MVC.
Scenario is. Using a 3rd party upload library for images. When a form is submitted, I want to make a call via ajax to submit the data and return the inserted item id. I then use that id for the 3rd party upload library to build folders where the images will be uploaded to.
I have the ajax call working and inserting the data to the database and getting the inserted id. But when the debug returns from the controller, it renders the id as a whole page.
Missing something fundamental here to MVC I think.
cshtml file:
<div class="col-md-8">
<input type="submit" value="Add Item" id="submitItem" />
<script>
$(document).ready(function () {
$("#submitItem").submit(function () {
event.preventDefault();
insertData();
});
});
function insertData()
{
var requestData = {
userID: $("#hdnUserID").val(),
title: $("#title").val(),
typeID: $("#typeID").val(),
description: $("#description").val()
};
$.ajax({
url: '<%= Url.Action("ItemUserDashBoard", "Home") %>',
type: 'post',
data: JSON.stringify(requestData),
dataType: 'json',
success: function (data) {
// your data could be a View or Json or what ever you returned in your action method
// parse your data here
alert(data);
$("#fine-uploader-gallery").fineUploader("uploadStoredFiles");
},
processData: false
});
}
</script>
</div>
HomeController.cs
[HttpPost]
public JsonResult ItemUserDashBoard(ItemAppraise.Models.iaDashBoardModel objItemUserDashBoard)
{
if(ModelState.IsValid)
{
using (dbContext)
{
ia_items iaItem = new ia_items
{
userID = objItemUserDashBoard.iaItems.userID,
typeID = objItemUserDashBoard.iaItems.typeID,
title = objItemUserDashBoard.iaItems.title,
description = objItemUserDashBoard.iaItems.description,
lastUpdate = DateTime.Now
};
dbContext.ia_items.Add(iaItem);
dbContext.SaveChanges();
//objItemUserDashBoard.iaItems.itemID = iaItem.itemID;
return Json(iaItem.itemID.ToString());
}
}
else{
return null;
}
}
Fiddler shows it as having a header of Content-Type: application/json; charset=utf-8.
But the page renders under the control url 'http://localhost:55689/Home/ItemUserDashBoard' with just the item id showing.
How do I get the data back just to use in the success part of the ajax call and not be rendered? Is this Partial Views or something similar?
Any guidance is appreciated.
In standard MVC. Any call made to a controller is handled just like a web request. So if i understand you correctly - the result of your httpPost is being rendered instead of the desired View? This is because you are returning JSON, so the controller assumes that is what you are trying to render. If you want a View to be rendered instead (and somehow use that response data) you could try setting the return type to ActionResult and returning a View("nameofview"); You can pass your response data to that view in a number of ways.
As a side note I think the problem you are facing could be better solved with Web Api instead of MVC. It works well with MVC and could be a simpler way of implementing your desired functionality. Separating your post requests and database interactions from the logic which decides which View to return.

Krajee bootstrap-fileinput with Mvc razor

I want to use Krajee bootstrap-fileinput (http://plugins.krajee.com/file-input) with Mvc razor, Please help me out with the process to to upload images to server and json result from actionResult.
I have just included a required js and css files in my view page and added a line
<input id="input-702" name="kartik-input-702[]" type="file" multiple="true" class="file-loading">
and a script
$("#input-702").fileinput({
uploadUrl:"#Url.Action("upload","Home")",
uploadAsync: true,
minFileCount: 1,
maxFileCount: 5,
overwriteInitial: false,
initialPreview: "",
initialPreviewConfig:"",
uploadExtraData: ""
});
This line is getting formatted and showing a drag and drop effect and select file button.The file selection and Thumbnail creation is working properly but on upload action there is the (fileinput,js) function "ajaxSubmit" which use to post the content to HomeController ActionResult "Upload".
ajaxSubmit: function (fnBefore, fnSuccess, fnComplete, fnError) {
var self = this, settings;
self.uploadExtra();
settings = $.extend({
xhr: function () {
var xhrobj = $.ajaxSettings.xhr();
return self.initXhr(xhrobj, 98);
},
url: self.uploadUrl,
type: 'POST',
dataType: 'json',
data: self.formdata,
cache: false,
processData: false,
contentType: false,
beforeSend: fnBefore,
success: fnSuccess,
complete: fnComplete,
error: fnError
}, self.ajaxSettings);
self.ajaxRequests.push($.ajax(settings));
},
Now i want to save all the files to server which are not uploaded using ActionResult and pass a value back to js. how to retrieve formdata and process.??
I was trying to find the solution to above problem and finally found the one. As I am able to save the file at server location from the controller but unfortunately I could not send the json response from controller to javascript.
Saving image using controller action :
[HttpPost]
public ActionResult upload()
{
foreach (string item in Request.Files)
{
HttpPostedFileBase file = Request.Files[item] as HttpPostedFileBase;
string fileName = file.FileName;
string UploadPath = "~/Images/";
if (file.ContentLength == 0)
continue;
if (file.ContentLength > 0)
{
string path = Path.Combine(HttpContext.Request.MapPath(UploadPath), fileName);
string extension = Path.GetExtension(file.FileName);
file.SaveAs(path);
}
}
return Json("");
}
To implement the delete button we have to Send Data from server in Asynchronous mode as a json array object eg.
initialPreview: [
'<img src='/images/desert.jpg' class='file-preview-image' alt='Desert' title='Desert'>',
],
initialPreviewConfig: [
{
caption: 'desert.jpg',
width: '120px',
url: '/localhost/avatar/delete',
key: 100,
extra: {id: 100}
}
]
Can anybody help me out to create json array object in controller and send it as a response object.???
I have a similar problem. Got it working (with the ajax calls) but always get one file in the request (whereas I need to get multiple but should be working for you!)
My code is as follows:
HTML:
<input id="input-id" type="file" data-preview-file-type="text" name="fileUpload[]" multiple class="file-loading" />
JS:
$("#input-id").fileinput(
{
uploadUrl: "/Galleries/Upload",
uploadAsync: true,
maxFileCount: 5
});
MVC controller which I would expect to be working - but i not:
[HttpPost]
public JsonResult Upload(IEnumerable<HttpPostedFileBase> fileUpload)
{
//somde logic
}
However when in side the method I will call:
Request.Files
My scenerio is that user:
clicks on 'browse'
selects picture and is able to see it in the preview
click on 'browse' once again
selects picture and the picture is appended to the current preview list
clicks upload and I get all the files in the controller
The only way I figure it, how it could be working is the ajax call switch on the plugin which allows to append the preview list. Unfortunatelly I can't submit all the pictures to the controller then.

Returning JSON with web api controller MVC

I am trying to convert a regular old controller I was using to an API controller and am having a little bit of difficulty. What these series of functions do is, in the jQuery, it iterates over a file containing all the usernames of employees and for each username it makes a call to the PopulateEmployee method in my webapi controller which should return JSON and then populate a results div.
When manually navigating to
..domain../staffinformation/populateemployee/employeeusername
I get the error
This XML file does not appear to have any style information associated with it. The
document tree is shown below.
<Error>
<Message>
The requested resource does not support http method 'GET'.
</Message>
</Error>
Please note that the div it will be populating is a partial view in an Umbraco CMS page and I don't think that is the problem but if you guys think differently please tell me.
There has to be something I am missing either with webAPI routing or something else.
Thanks for your help.
Here's the codez.
Please notice that this method has the HttpPost tag
public class StaffInformationController : ApiController
{
[System.Web.Http.ActionName("PopulateEmployee")]
[System.Web.Http.HttpPost]
public StaffListing PopulateEmployee(string id)
{
//do error checking on input
StaffListing staffListing = new StaffListing(id);
//populate other fields
return staffListing;
}
}
The routing set up for the api controller
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
The jQuery call specifying use of 'POST', please forgive the trickiness of the recursive call in this function.
function getEmployeeObjectByIndex() {
$.ajax({
url: $('#root').val() + '/api/StaffInformation/PopulateEmployee',
type: 'POST',
async: true,
contentType: 'application/json, charset=utf-8',
data: JSON.stringify({ 'username': lines[i] }),
success: function (staffObject) {
if (!(staffObject.Name == undefined)) {
buildHtmlStrings(staffObject);
}
i++;
getEmployeeObjectByIndex(); //recursive call
}
});
}
manually navigating to that address throws the error because, when manually navigating you are doing a GET (and your method only allows POSTs).
You should fire up Fiddler and watch the ajax POST request and response to see how the server is responding / your request is being made
Jquery ------> web api
Web API has one property i.e. CONTENT NEGOTIATION means you send any data and accept any data as you want.
$.ajax({
contentType: 'application/json, charset=utf-8',
// this is sending your data of datatype json to server, here you send any type of data
accept: 'application/json',
//this is receiving/getting data form server to client...
// SO HERE YOU GET JSON DATA AS YOU WANT only mention which data of datatype u want...
//if you sending xml and you want json so only write accept as json it get automatically converted into your required datatype..by MediaTypeFormatter
});

Passing JSON object to MVC Controller

I can successfully make a jQuery Ajax call into my C# Controller and receive back an XML string, but I need to in turn gather some Portfolio dates and package them up into a JSON object so I can send them back into another C# Controller.
If it's a C# issue, then I apologize if I'm in the wrong forum...however I'd like to pass my JSON object into the server side controller ..
Here's what I'm trying to do:
var nodeDatesJson = {"nodedates": // CREATE JSON OBJECT OF DATE STRINGS
{ "date": 01/20/2012,
"date": "01/21/2012" } };
getTradeContribs(thisPfId, nodeDatesJson.nodedates.date);
Now call the next js function:
function getTradeContribs(pfid, nodedates) {
//alert(nodedates);
$.ajax({ // GET TRADE CONTRIBS FROM SERVER !!
url: "/Portfolios/getTradeContribs?portfolioId=" + pfid + "&nodedates=" + nodedates,
type: "GET", // or "PUT"
dataType: "json",
async: true,
success: parseTradeContribs,
error: function (error) {
alert("failed in opening Trade Contribs file !!!");
}
});
}
function parseTradeContribs(data) {
alert("In parseTradeContribs..." );
$(data).find("Trade").each(function(){
$(".TradeContrib").append($(this).text());
})
}
and my C# controller is trying to read in the "nodedates" JSON object, but HOW do I read it in ?
public string getTradeContribs(string portfolioId, **string nodedates**)
{
// Build Portfolio Select request here !
RequestBuilder rzrRequest = new RequestBuilder();
// REQUEST FOR CONTRIBUTIONS !
// ... more code here..
xmlResponse.LoadXml(contribResponse);
string jsonTest = #" {""nodedates"": ""date"":""01/01/2012""}";
//return xmlResponse.OuterXml; // WORKS FINE
return "<Trade><TradeId>1234</TradeId></Trade>"; // RETURN TEST XML STR
}
thank you in advance...
Bob
The best way to receive a list of dates in a MVC action is to bind to a collection. What this means is that you should put your dates and other attributes in a form with the following naming convention:
<input type="hidden" name="dates" value="2012-1-20" />
<input type="hidden" name="dates" value="2012-1-21" />
Then you should serialize this form (look into jquery's docs for this) and post its data to your action, which will be something along the lines of:
public ActionResult getTradeContribs(string portfolioId, IList<DateTime> dates) {
// Do your work here
}
You should really take a look into MVC Model binding and collection binding as well:
Model binding to a list
Model binding objects
Also, if I may, your javascript object has two properties with the same name, which is probably not what you mean. If you want to have multiple dates stored somewhere in a object, you should use an array:
var nodeDatesJson = {"nodedates":
[ "01/20/2012", "01/21/2012" ] };
Sorry, but I didn't understand your doubt very well...but here it goes:
Maybe you should pass the json, well-formatted, as a string and use some C# parser.
This way you can get a object in server-side as same as the Json object in javascript.
=]

AJAX response using Jquery (with zend framework) contains unwanted HTML Code

Currently, the following code works as intended but if I add an echo such as "LANG: en" anywhere in the code (let's say in the bootstrap), the following code won't work anymore and I get this ajax request response :
<br/>LANG : en{"response":true,"id":13}
(the ajax response contains the echo + json array ) and therefore I'm not able to print the id (it will print : undefined when i will try to access to data.id).
My question is : How can I print my debug info and still manage to perform ajax requests ?
Here is my code in the controller :
public function init()
{
$this->_helper->ajaxContext->addActionContext('retrievecategories', 'json')->initContext();
}
public function retrievecategoriesAction()
{
$this->_helper->layout()->disableLayout();
$this->_helper->viewRenderer->setNoRender(true);
if ($this->getRequest()->isXmlHttpRequest()) {
if (isset($_POST['id']))
$id = $_POST['id'];
$id+=1;
echo json_encode(array('response' => true, 'id' => $id));
}
}
My js code :
jQuery(function(){
var obj = {"id":12};
jQuery.ajax({
url: '/search/retrievecategories?json',
type: 'post',
data: obj,
dataType: 'json',
success: function(data){
var id = data.id;
alert(id);
},
error: function(data){
var id = data.id;
alert(id);
}
});
});
I hope I was clear enough. Thank you for your time !
If you echo anything but the JSON object, the JQuery parser will fail because the response is no longer a valid JSON. you could make a custom parser which interprets the response text and takes away the debug info leaving the JSON object, or you can include the debug info in the array you encode.
json_encode(array('data'=>'data','debug'=>'debug info'))
Then you detect if the debug field is present and after a console.log() or alert() you delete it form the object.
I would strongly recommend that you read about firePHP. It uses the same console that Firebug uses to display debug information from your php code. It is really simple to use with the Zend_Log.