Send multipart request from ajax to spring controller without form? - javascript

I am uploading an image from the desktop, and converting this image into base code in javascript. After that I want to send this image base code to spring controller with the multipart request. But I am not using Form.
HTML
<input id="inputFileToLoad" type="file" onchange="encodeImageFileAsURL()">
JAVA SCRIPT
window.photoCakeUrl = '<c:url value="/media/image/upload"/>';
function encodeImageFileAsURL() {
var filesSelected = document.getElementById("inputFileToLoad").files;
if (filesSelected.length > 0) {
var fileToLoad = filesSelected[0];
var fileReader = new FileReader();
fileReader.onload = function (fileLoadedEvent) {
var srcData = fileLoadedEvent.target.result; // <--- data: base64
var newImage = document.createElement('img');
var photoCake = srcData;
newImage.src = srcData;
document.getElementById("imgTest").innerHTML = newImage.outerHTML;
var ajax1 = $.ajax({
type: 'POST',
url: photoCakeUrl,
processData: false, // important
contentType: false, // important
dataType: 'json',
data: {photoCak: photoCake}
});
});
},
fileReader.readAsDataURL(fileToLoad);
}
}
SPRING CONTROLLER:
#RequestMapping(value = "/media/image/upload", method = RequestMethod.POST)
#ResponseBody
public Map<String, String> productPictureUploadnew(MultipartHttpServletRequest request, HttpServletResponse response) {
Map<String, String> resp = new HashMap<>();
String photoCake = request.getParameter("photoCak");
System.out.println("photoCake " + photoCake);
return resp;
}
But when I am generating AJAX call then 500 error will comes. If i am using simply
public Map<String, String> productPictureUploadnew(HttpServletRequest
request, HttpServletResponse response)
Then it works. Mean when I am using MultipartHttpServletRequest place of HttpServletRequest
request then it is not works.

I got solution, We can use formData in javascript without using form in any JSP to send MultipartHttpServletRequest.
window.photoCakeUrl = '<c:url value="/media/image/upload"/>';
function encodeImageFileAsURL() {
var filesSelected = document.getElementById("inputFileToLoad").files;
if (filesSelected.length > 0) {
var fileToLoad = filesSelected[0];
var fileReader = new FileReader();
fileReader.onload = function (fileLoadedEvent) {
var srcData = fileLoadedEvent.target.result; // <--- data: base64
var newImage = document.createElement('img');
var photoCake = srcData;
newImage.src = srcData;
document.getElementById("imgTest").innerHTML = newImage.outerHTML;
var formData = new FormData();
formData.append("imgFile", document.getElementById("inputFileToLoad").files[0]);
var ajax1 = $.ajax({
type: 'POST',
url: photoCakeUrl,
dataType: 'json',
data: {photoCak: photoCake}
});
});
},
fileReader.readAsDataURL(fileToLoad);
}
}
var formData = new FormData();
formData.append("imgFile", document.getElementById("inputFileToLoad").files[0]);
Controller:
#RequestMapping(value = "/media/image/upload", method = RequestMethod.POST)
#ResponseBody
public Map<String, String> productPictureUploadnew(MultipartHttpServletRequest request, HttpServletResponse response) {
Map<String, String> resp = new HashMap<>();
System.out.println("fsasasafsafsafsafsa");
Iterator<String> itr = request.getFileNames();
String photoCake = request.getParameter("photoCak");
File file;
----------
-------
----------
return resp;
}
Thanks you, I hope this is help full for you guys.

You are sending it as multipart/form-data may be that's why HttpServletRequest isn't able to get your data , remove contentType option from ajax call then jquery will use the defaylt wiz. 'application/x-www-form-urlencoded; charset=UTF-8'
var ajax1 = $.ajax({
type: 'POST',
url: photoCakeUrl,
processData: false, // important
dataType: 'json',
data: {photoCak: photoCake}
});

This is how I would have done it:
window.photoCakeUrl = '<c:url value="/media/image/upload"/>';
window.URL = window.URL || window.webkitURL
function encodeImageFileAsURL() {
var filesSelected = $('#inputFileToLoad')[0].files;
if (filesSelected.length) {
var fileToLoad = filesSelected[0];
var img = new Image();
var formData = new FormData();
formData.append('imgFile', fileToLoad);
img.onload = function() {
// only append the image once it's loaded so we don't append broken images
$('#imgTest').html(this);
URL.revokeObjectURL(this.src); // Release memory
// Uploading a image when we can ensure it's a image that can be loaded
fetch(photoCakeUrl, {method: 'POST', body: formData});
}
img.onerror = function() {
// You didn't upload a image
}
img.src = URL.createObjectURL(srcData);
}
}
URL.createObjectURL is faster and uses less memory then a long base64 string that is also ~3x larger in size and uses 2x more memory since it's stored in utf16 and not utf8
You can use new Image which is a nicer sorter version of createElement('img')
Then I would also use Fetch instead of $.ajax cuz jQuery handle formData stupidly (need to set processData & contentType to false)
Then i would also add the accept="images/*" attribute to the file input to filter out images

Related

Send byte array from code behind to ajax call

I have a web method in which I convert a HTML to PDF and then save it to a local folder, I want the user to download that file without making a post back, so I'm trying to make an AJAX POST call into a web method to get the byte array and then convert it into a PDF, the problem is that I get an error 500:
{Message: "There was an error processing the request.", StackTrace: "", ExceptionType: ""}
Although I know the web method triggers, because when placing a breakpoints it stops there and I can actually see the binary array before the return as well as the created file on the folder, I still get the error massage, here is my code:
C#:
[WebMethod]
public static byte[] getfile(string one, string two)
{
HttpContext context = HttpContext.Current;
HtmlToPdf converter = new HtmlToPdf();
converter.Options.MinPageLoadTime = 10;
converter.Options.MaxPageLoadTime = 30;
PdfDocument doc = converter.ConvertUrl("http://localhost/dashboard_pdf.aspx?one=" + one+ "&" + "two=" + two);
string appPath = HttpContext.Current.Request.ApplicationPath;
Random rnd = new Random();
int num = rnd.Next(1, 1000000);
string path = context.Server.MapPath(appPath + "/Web/" + num + ".pdf");
doc.Save(path);
doc.Close();
FileStream stream = File.OpenRead(path);
byte[] fileBytes = new byte[stream.Length];
stream.Read(fileBytes, 0, fileBytes.Length);
stream.Close();
byte[] b1 = System.IO.File.ReadAllBytes(path);
return fileBytes;
}
JS:
$.ajax({
type: "POST",
url: "dashboard.aspx/getfile",
contentType: "application/json; charset=utf-8",
data: "{'one':\"" + one+ "\", 'two':\"" + two + "\" }",
dataType: "json",
processData: false,
success: function (data) {
data = data.d;
var byteArray = new Uint8Array(data);
var a = window.document.createElement('a');
a.href = window.URL.createObjectURL(new Blob([byteArray], { type: 'application/pdf' }));
a.download = "Dashboard";
document.body.appendChild(a)
a.click();
document.body.removeChild(a)
}
});
Any ideas?
Thanks.
I solve this by adding this into my web.config:
<system.web.extensions>
<scripting>
<webServices>
<!-- Update this value to change the value to a larger value that can accommodate your JSON Strings -->
<jsonSerialization maxJsonLength="86753090" />
</webServices>
</scripting>
</system.web.extensions>
var jsonResult = Json(model, JsonRequestBehavior.AllowGet);
jsonResult.MaxJsonLength = int.MaxValue;
return jsonResult;
In this way you return the maximum byte array and can be able to convert to PDF and download

Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded error

I know that the above question has been asked many times. But those did not solve my problem.
Here is the problem statement :
I am trying to download zip file using 'ajax', I have read many posts that FILE DOWNLOAD IS NOT POSSIBLE USING AJAX
So I tried to hack it, I don't know my approach is correct or not, I just tried it.
So what am I doing is .. I am sending the byte from My controller. to my ajax call, and trying to make it downloadable.
here is my ajax call
$.ajax({
type: "POST",
url: 'myURL',
data: JSON.stringify(ajaxData),
dataType: "json",
contentType: "application/json",
crossDomain: true,
accept: "application/zip",
success: function (data) {
// i get the data here from my controller
var sampleBytes = base64ToArrayBuffer(data);
saveByteArray([sampleBytes], 'black1x1.gif');
function base64ToArrayBuffer(base64) {
console.log("base64ToArrayBuffer called");
var binaryString = window.atob(base64);
var binaryLen = binaryString.length;
var bytes = new Uint8Array(binaryLen);
for (var i = 0; i < binaryLen; i++) {
var ascii = binaryString.charCodeAt(i);
bytes[i] = ascii;
}
return bytes;
}
var saveByteArray = (function () {
var a = document.createElement("a");
document.body.appendChild(a);
a.style = "display: none";
return function (data, name) {
var blob = new Blob(data, { type: "octet/stream" }),
url = window.URL.createObjectURL(blob);
a.href = url;
a.download = name;
a.click();
window.URL.revokeObjectURL(url);
};
}());
},
error: function (data) {
}
});
But when I convert the data to base64, I get the above error.
please, don't mind, I might be doing some foolish thing, I just tried,
can any one help me to solve the problem.

Converting HTML canvas to binary image data

I need help with HTML canvas element.I'm new to HTML.
I need to capture image from the webcam and send it to Microsoft cognitive API to find the emotions in the picture.
The API accepts image in octet-stream. The API is https://westus.dev.cognitive.microsoft.com/docs/services/5639d931ca73072154c1ce89/operations/563b31ea778daf121cc3a5fa
The code is
canvas = document.getElementById("myCanvas");
ctx = canvas.getContext('2d');
dataUrl = canvas.toDataURL("image/png");
$.ajax({
url: apiUrl,
beforeSend: function(xhrObj) {
xhrObj.setRequestHeader("Content-Type", "application/octet-stream");
xhrObj.setRequestHeader("Ocp-Apim-Subscription-Key", apiKey);
},
type: "POST",
data: dataUrl,
processData: false
}).done(function(response) {
...
});
HTTP Response code is 400 and the response message is as below.
{"error":{"code":"BadBody","message":"Invalid face image."}}
logging the dataUrl shows the data as
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAAEsCAYAAAB5fY51AAAgAElEQVR4XqS92bOm2Vnlt7/pZGZVCU3IGkFCDhoxChDQBknQtGUBJtzd4Vvf+a7RUFklqVQC/xu.....
I have tried by removing data:image/png but no use.
I'm right canvas.toDataURL returns string form of base64 encoded data of the image. I can display this image on html page. I also did a right click saved it to local drive, and called API with file, it works.
So, the issue would be while moving the data from canvas element to the request body in binary format.
How can this be done ?. Thanks in advance for your help.
This might work. Try creating Blob from your dataUrl and pass it in to the ajax, as:
function createBlob(dataURL) {
var BASE64_MARKER = ';base64,';
if (dataURL.indexOf(BASE64_MARKER) == -1) {
var parts = dataURL.split(',');
var contentType = parts[0].split(':')[1];
var raw = decodeURIComponent(parts[1]);
return new Blob([raw], { type: contentType });
}
var parts = dataURL.split(BASE64_MARKER);
var contentType = parts[0].split(':')[1];
var raw = window.atob(parts[1]);
var rawLength = raw.length;
var uInt8Array = new Uint8Array(rawLength);
for (var i = 0; i < rawLength; ++i) {
uInt8Array[i] = raw.charCodeAt(i);
}
return new Blob([uInt8Array], { type: contentType });
}
in ajax, pass the blobData,
...
var blobData = createBlob(dataUrl);
$.ajax({
url : apiUrl,
beforeSend : function(xhrObj) {
xhrObj.setRequestHeader("Content-Type", "application/octet-stream");
xhrObj.setRequestHeader("Ocp-Apim-Subscription-Key", apiKey);
},
type : "POST",
data : blobData,
processData : false
}).done(function(response) {...}

Save response as file

I have WebAPI method which returns HttpResponseMessage with .csv file as Content:
private static HttpResponseMessage FileAsAttachment(string file)
{
var now = DateTime.Now;
var result = new HttpResponseMessage(HttpStatusCode.OK);
result.Content = new StringContent(file);
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment"); //attachment will force download
result.Content.Headers.ContentDisposition.FileName = string.Format("Report-{0}.csv", now.ToString("MMMM"));
return result;
}
So I have just click function, which make call to server :
$scope.GenerateReport = function() {
var endDate = '2016-04-30';
UserDaysSummary.generateReport({endDate: endDate }, function (result) {
console.log("Export");
});
}
But all that I've got - is a response with data inside.
I've tried to get it as file using this and this answer, but this doesn't change anything.
Preferably, that call to the server has GET method, btw
Is your GenerateReport function returning a promise? Try this:
userDaysSummary.generateReport = function(endDate) {
var defer = $q.defer();
$http.get('path/to/api', { endDate: endDate }, { responseType: 'arrayBuffer' }).then(function(data, status, headers, config) {
var results = {
data: data, //your file is here
headers: headers(), //headers are here
status: status,
config: config
};
//return a success promise containing the response object
defer.resolve(results);
}, function(data, status, headers, config) {
defer.reject(data);
});
return defer.promise;
}
Then, using the promise to download the file:
userDaysSummary.generateReport(endDate).then(function(response) {
//get the file
var octetStreamMime = 'application/octet-stream';
//get the headers' content disposition
var cd = response.headers["content-disposition"];
//get the file name with regex
var regex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
var match = regex.exec(cd);
//is there a fiel name?
var fileName = match[1] || "myDefaultFileName.csv";
//replace leading and trailing slashes that C# added to your file name
fileName = fileName.replace(/\"/g, "");
//determine the content type from the header or default to octect stream
var contentType = response.headers["content-type"] || octetStreamMime;
//finally, download it
try {
var blob = new Blob([response.data], {type: contentType});
//downloading the file depends on the browser
//IE handles it differently than chrome/webkit
if (window.navigator && window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveOrOpenBlob(blob, fileName);
} else {
var objectUrl = URL.createObjectURL(blob);
window.open(objectUrl);
}
} catch (exc) {
console.log("Save Blob method failed with the following exception.");
console.log(exc);
}
}, function(error) {
//an error occurred while trying the API, handle this
});

How to attach a PDF generated using jsPDF to the mail using asp.net c#

I need to know if there is any way to attach a PDF file generated using jsPDF and mail it in asp.net C#?
I have the following code in c#
MailMessage message = new MailMessage(fromAddress, toAddress);
message.Subject = subject;
message.IsBodyHtml = true;
message.Body = StrContent.ToString();
//message.Attachments.Add(new Attachment("getDPF()"));
smtp.Send(message);
and I'm using a JsPDF library as follows:
<script type="text/javascript" src="jsPdf/jspdf.min.js"></script>
<script type="text/javascript">
function getPDF()
{
var doc = new jsPDF();
doc.text(20, 20, 'TEST Message');
doc.addPage();
//doc.save('volt.pdf');
}
</script>
Is there any way to attach it in the mail before send it?
Thanks in advance.
You cannot call client-side code (Javascript function) from server code (c#).
You can only communicate via the (HTTP/HTTPs) protocol.
I think you need to generate the PDF from the client and then send that PDF to server so that you can attach the PDF to an email.
In that case you need to first generate the PDF and send it to the server as a base64 string.
You can then convert the base64 string to PDF in C# and mail it as an attachment.
Client Side:
function generatePdf() {
var doc = new jsPdf();
doc.text("jsPDF to Mail", 40, 30);
var binary = doc.output();
return binary ? btoa(binary) : "";
}
Posting the base64 pdf content to the server:
var reqData = generatePdf();
$.ajax({
url:url,
data: JSON.stringify({data:reqData}),
dataType: "json",
type: "POST",
contentType: "application/json; charset=utf-8",
success:function(){}
});
On the server (MVC Controller):
public ActionResult YourMethod(string data)
{
//create pdf
var pdfBinary = Convert.FromBase64String(data);
var dir = Server.MapPath("~/DataDump");
if (!Directory.Exists(dir))
Directory.CreateDirectory(dir);
var fileName = dir + "\\PDFnMail-" + DateTime.Now.ToString("yyyyMMdd-HHMMss") + ".pdf";
// write content to the pdf
using (var fs = new FileStream(fileName, FileMode.Create))
using (var writer = new BinaryWriter(fs))
{
writer.Write(pdfBinary, 0, pdfBinary.Length);
writer.Close();
}
//Mail the pdf and delete it
// .... call mail method here
return null;
}
Check out here for more information https://github.com/Purush0th/PDFnMail
Your code example use pdf.text(), but in most situations, you want to export a html page with table(s) or image(s). The latest version jsPDF html PlugIn instead of addHtml(). Below is an code example using jsPDF html() and Web API.
Client side:
function emailHtml() {
let pdf = new jsPDF('p', 'pt', 'a3'); // a4: part of the page is cut off?
pdf.html(document.body, {
callback: function (pdf) {
let obj = {};
obj.pdfContent = pdf.output('datauristring');
var jsonData = JSON.stringify(obj);
$.ajax({
url: '/api/jspdf/html2pdf',
type: 'POST',
contentType: 'application/json',
data: jsonData
});
}
});
}
Note that the datauristring returned from pdf.html has a filename added to the string, filename=generated.pdf;. Also, SmtpClient is obsolete, consider to use MailKit instead.
[Route("[action]")]
[HttpPost]
public void Html2Pdf([FromBody] JObject jObject)
{
dynamic obj = jObject;
try
{
string strJson = obj.pdfContent;
var match = Regex.Match(strJson, #"data:application/pdf;filename=generated.pdf;base64,(?<data>.+)");
var base64Data = match.Groups["data"].Value;
var binData = Convert.FromBase64String(base64Data);
using (var memoryStream = new MemoryStream())
{
var mail = new MailMessage
{
From = new MailAddress("[FromEmail]")
};
mail.To.Add("");
mail.Subject = "";
mail.Body = "attached";
mail.IsBodyHtml = true;
mail.Attachments.Add(new Attachment(new MemoryStream(binData), "htmlToPdf.pdf"));
var SmtpServer = new SmtpClient("[smtp]")
{
Port = 25,
Credentials = new NetworkCredential("[FromEmail]", "password"),
EnableSsl = true
};
SmtpServer.Send(mail);
}
}
catch (Exception ex)
{
throw;
}
}

Categories