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
Related
I have an ASP.Net Web API method which is returning a zip file, which seems happening properly, now what I want is, I want to download that zip file at the client location using React. My Api method is as follows:
[HttpPost]
public FileContentResult Post([FromForm] string communityName, [FromForm] string files)
{
var removedInvalidCharsFromFileName = removeInvalidCharsFromFileName(files);
var tFiles = removedInvalidCharsFromFileName.Split(',');
string rootPath = Configuration.GetValue<string>("ROOT_PATH");
string communityPath = rootPath + "\\" + communityName;
byte[] theZipFile = null;
using (MemoryStream zipStream = new MemoryStream())
{
using (ZipArchive zip = new ZipArchive(zipStream, ZipArchiveMode.Create, true))
{
foreach (string attachment in tFiles)
{
var zipEntry = zip.CreateEntry(attachment);
using (FileStream fileStream = new FileStream(communityPath + "\\" + attachment, FileMode.Open))
using (Stream entryStream = zipEntry.Open())
{
fileStream.CopyTo(entryStream);
}
}
}
theZipFile = zipStream.ToArray();
}
return File(theZipFile, "application/zip", communityName + ".zip");
}
And my React/JS method is as follows:
handleDownload = (e) => {
e.preventDefault();
var formData = new FormData();
formData.append('communityname', this.state.selectedCommunity);
formData.append('files', JSON.stringify(this.state['checkedFiles']));
let env = 'filesApi.' + clientConfiguration['Environment'];
let url = clientConfiguration['filesApi.local'];
alert(url);
axios({
method: 'post',
url: url,
data: formData
})
.then(res => {
//console.log(res.data);
var binaryData = [];
binaryData.push(res.data);
const src = window.URL.createObjectURL(new Blob(binaryData, { type: "application/zip" }));
var fileName = `${this.state['selectedCommunity']}.zip`;
saveAs(src, fileName);
});
};
It is downloading the zip file, but says the following error when I try to unzip the file at the client location, what am I missing - not able to understand:
Can not open the file as zip archive, is not archiving, Warning Headers error
, any help please
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
I am working with an ASP .NET Web API where the POST function of the API is returning a byte array like so in the C# code:
return Ok(outputStream.ToArray());
Where outputStream is of type System.IO.MemoryStream and the ToArray() is returning a byte array.
This function is returning a PDF stream that I want to display to the users in their browser or at least let them save it.
I've ran across a JavaScript example from Stack Overflow that shows how to get a Blob from a Base64 encoded string and display it and I was able to get it working when the API returned a Base64 encoded string; however, I wasn't able to get it working when the API was return the byte array as shown before.
May I get some code examples of how to get it working when the API is returning a byte array?
My JQuery Ajax POST request looks like:
function LoadPDF() {
var args = [];
var x = $.ajax({
type: "POST",
url: "DirectoryQuery.aspx/GetFullPdf",
contentType: "application/json; charset=UTF-8",
responseType: "text/plain; charset=UTF-8",
async: true,
dataType: "json",
processData: "false",
success: OnSuccess,
error: OnErrorCall
});
function OnSuccess(response) {
var byteArray = new Uint8Array(response.d);
saveTextAsFile("document.pdf", byteArray);
}
function OnErrorCall(response) {
console.log(response);
//location.reload();
}
}
Try file-save-as.js, like this:
function saveTextAsFile(fileNameToSaveAs, textToWrite) {
/* Saves a text string as a blob file*/
var ie = navigator.userAgent.match(/MSIE\s([\d.]+)/),
ie11 = navigator.userAgent.match(/Trident\/7.0/) && navigator.userAgent.match(/rv:11/),
ieEDGE = navigator.userAgent.match(/Edge/g),
ieVer = (ie ? ie[1] : (ie11 ? 11 : (ieEDGE ? 12 : -1)));
if (ie && ieVer < 10) {
console.log("No blobs on IE ver<10");
return;
}
var textFileAsBlob = new Blob([textToWrite], {
type: 'text/plain'
});
if (ieVer > -1) {
window.navigator.msSaveBlob(textFileAsBlob, fileNameToSaveAs);
} else {
var downloadLink = document.createElement("a");
downloadLink.download = fileNameToSaveAs;
downloadLink.href = window.URL.createObjectURL(textFileAsBlob);
downloadLink.onclick = function (e) { document.body.removeChild(e.target); };
downloadLink.style.display = "none";
document.body.appendChild(downloadLink);
downloadLink.click();
}
}
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;
}
}
I have a webservice which returns a byte[] to the client, to show images.
This image is stored in a json object, see fiddle: http://jsfiddle.net/FuGN8/
the array of numerics is assigned to result after i do a simple line of:
result = result["d"];
This is fetched via a AJAX call, so i want to render an image from this data.
Naturally, doing something like:
$("img#mytag").attr("src", result);
would not do what i want.
Is there a javascript command which would do what i am intending?
my Server side code I changed to do:
WebClient wsb = new WebClient();
string url = "...";
byte[] resp = wsb.DownloadData(url);
UTF8Encoding enc = new UTF8Encoding();
return enc.GetString(resp);
but on the client side, since i do not know what the image type would be, i was attempting:
src="data:image/*;base64,"+RET_VAL
and it wasnt doing anything. On a similar note, i also tried:
src="data:image;base64,"+RET_VAL
since the above was doing UTF8 encoding, i also added in a the following:
src:"data:image;base64,"+window.btoa(unescape(encodeURIComponent( RET_VAL )))
You are not using Base64 encoding in your image. Use the method Convert.ToBase64String instead. You could also send the image type in the JSON response in order to apply it to the src attribute. I could get it to work with this code:
[WebMethod]
[ScriptMethod(UseHttpGet = true, ResponseFormat = ResponseFormat.Json)]
public string SendImage()
{
var path = #"C:\teste.png";
byte[] bytes = File.ReadAllBytes(path);
Image image = null;
using (var stream = new MemoryStream(bytes))
image = Image.FromStream(stream);
var json = new Dictionary<string, object>();
json.Add("type", new ImageFormatConverter().ConvertToString(image.RawFormat).ToLower());
json.Add("contents", Convert.ToBase64String(bytes));
return new JavaScriptSerializer().Serialize(json);
}
And this JavaScript code:
$.ajax({
type: 'GET',
url: 'WebService1.asmx/SendImage',
contentType: 'application/json; charset=utf-8',
success: function (response) {
var data = JSON.parse(response.d);
$('<img />').attr('src', 'data:image/' + data.type + ';base64,' + data.contents).appendTo('body');
}
})
Of course you'll have to adapt it as you are using a WebClient to get your image.
The src attribute of your img element expects the image location (its URL), not the actual image bytes.
To put your data as an URL you may use the data URI Scheme. For example, for a .png image:
data:image/png;base64,<your image bytes encoded in base64>