I have a Windows Phone 8 client that makes the following post request:
public async Task<string> DoPostRequestAsync(String URI, JSonWriter jsonObject, ObservableCollection<byte[]> attachments)
{
var client = new RestClient(DefaultUri);
var request = new RestRequest(URI, Method.POST);
request.AddParameter("application/json; charset=utf-8", jsonObject.ToString(), ParameterType.RequestBody);
// add files to upload
foreach (var a in attachments)
request.AddFile("picture", a, "file.jpg");
var content = await client.GetResponseAsync(request);
return content;
}
From the RestSharp documentation i read that by adding files to a request it's automatically made as a "multipart/form-data" request.
The controller for the upload operation in Play 2.1 is as follows:
@BodyParser.Of(BodyParser.Json.class)
public static Result createMessage() {
JsonNode json = request().body().asJson();
ObjectNode result = Json.newObject();
String userId = json.findPath("userId").getTextValue();
String rayz = json.findPath("message").getTextValue();
Http.MultipartFormData body = request().body().asMultipartFormData();
Http.MultipartFormData.FilePart picture = body.getFile("picture");
if (picture != null) {
String fileName = picture.getFilename();
String contentType = picture.getContentType();
File file = picture.getFile();
result.put("status", "success");
result.put("message", "Created message!");
return badRequest(result);
} else {
result.put("status", "error");
result.put("message", "Message cannot be created!");
return badRequest(result);
}
}
Note that on the application.conf i have set the following in order to increase the size limit (seems not be working):
# Application settings
# ~~~~~
parsers.text.maxLength=102400K
Now, each time I am trying to make the POST request i noticed on the debugger that IsMaxSizeEsceeded variable is always true and that the multipart variable is null. When i tried to just upload one file nu using the following controller everything seemed to work normally. The size wasn't a problem and the multipart variable was set.
public static Result singleUpload() {
ObjectNode result = Json.newObject();
Http.MultipartFormData body = request().body().asMultipartFormData();
Http.MultipartFormData.FilePart picture = body.getFile("picture");
if (picture != null) {
String fileName = picture.getFilename();
String contentType = picture.getContentType();
File file = picture.getFile();
result.put("status", "success");
result.put("message", "File uploaded!");
return badRequest(result);
} else {
result.put("status", "error");
result.put("message", "File cannot be uploaded!");
return badRequest(result);
}
}
The problem is that the attachments/files should be sent/uploaded along with the JSON object to the server in a single POST Request and NOT separately.
Has anyone faced similar problems before? Is it possible to achieve this - Send a json object and multiple files to be uploaded on the server in a single POST request with Play 2.1?
Found the way to do it..posting it in case someone else tries to do something similar in the future.
So first of all the request from RestSharp client must be done in the following way:
public async Task<string> DoPostRequestWithAttachmentsAsync(String ext, JSonWriter jsonObject, ObservableCollection<byte[]> attachments) {
var client = new RestClient(DefaultUri);
var request = new RestRequest(ext, Method.POST);
request.RequestFormat = DataFormat.Json;
request.AddParameter("json", jsonObject.ToString(), ParameterType.GetOrPost);
// add files to upload
foreach (var a in attachments)
request.AddFile("attachment", a, "someFileName");
var content = await client.GetResponseAsync(request);
if (content.StatusCode != HttpStatusCode.OK)
return <error>;
return content.Content;
}
Now moving into Play the controller is as follows:
public static Result createMessage() {
List<Http.MultipartFormData.FilePart> attachments;
String json_str;
Http.MultipartFormData body = request().body().asMultipartFormData();
// If the body is multipart get the json object asMultipartFormData()
if (body!=null) {
json_str = request().body().asMultipartFormData().asFormUrlEncoded().get("json")[0];
attachments= body.getFiles();
}
// Else, if the body is not multipart get the json object asFormUrlEncoded()
else {
json_str = request().body().asFormUrlEncoded().get("json")[0];
attachments = Collections.emptyList();
}
// Parse the Json Object
JsonNode json = Json.parse(json_str);
// Iterate through the uploaded files and save them to the server
for (Http.MultipartFormData.FilePart o : attachments)
FileManager.SaveAttachmentToServer(o.getContentType(), o.getFile());
return ok();
}
So the mistakes in the RestSharp side seemed to be the ParameterType.RequestBody on the json object; and in the controller the size doesn't really changes anything.. but the important part is not to use the @BodyParser.Of(BodyParser.Json.class) since that would convert the whole request body into a json object. That combined with the files that are being send to the server triggers the isMaxSizeExceeded flag.
Finally the multipart file handling in the controller is as shown above, only tricky part is that the attachments are optional meaning that this must be handled.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With