I am generating PDF using wkhtmltopdf.exe with below code.
string url = HttpContext.Current.Request.Url.AbsoluteUri;
//string[] strarry = sPath.Split('/');
//int lengh = strarry.Length;
var pdfUrl = HtmlToPdf(pdfOutputLocation: "~/PDF/", outputFilenamePrefix: "DT", urls: new string[] { url });
WebClient req = new WebClient();
HttpResponse response = HttpContext.Current.Response;
response.Clear();
response.ClearContent();
response.ClearHeaders();
response.Buffer = true;
Response.ContentType = "application/pdf";
response.AddHeader("Content-Disposition", "attachment;filename=\"" + pdfUrl.ToString().Substring(6) + "\"");
byte[] data = req.DownloadData(Server.MapPath(pdfUrl.ToString()));
response.BinaryWrite(data);
File.Delete(Server.MapPath(pdfUrl.ToString()));
response.End();
and
public static string HtmlToPdf(string pdfOutputLocation, string outputFilenamePrefix, string[] urls,
string[] options = null,
string pdfHtmlToPdfExePath = "C:\\Program Files\\wkhtmltopdf\\wkhtmltopdf.exe")
{
string urlsSeparatedBySpaces = string.Empty;
try
{
//Determine inputs
if ((urls == null) || (urls.Length == 0))
throw new Exception("No input URLs provided for HtmlToPdf");
else
urlsSeparatedBySpaces = String.Join(" ", urls); //Concatenate URLs
string outputFolder = pdfOutputLocation;
string outputFilename = outputFilenamePrefix + "_" + DateTime.Now.ToString("yyyy-MM-dd-hh-mm-ss-fff") + ".PDF"; // assemble destination PDF file name
var p = new System.Diagnostics.Process()
{
StartInfo =
{
FileName = pdfHtmlToPdfExePath,
Arguments = ((options == null) ? "" : String.Join(" ", options)) + " " + urlsSeparatedBySpaces + " " + outputFilename,
UseShellExecute = false, // needs to be false in order to redirect output
RedirectStandardOutput = true,
RedirectStandardError = true,
RedirectStandardInput = true, // redirect all 3, as it should be all 3 or none
WorkingDirectory = HttpContext.Current.Server.MapPath(outputFolder)
}
};
p.Start();
// read the output here...
var output = p.StandardOutput.ReadToEnd();
var errorOutput = p.StandardError.ReadToEnd();
// ...then wait n milliseconds for exit (as after exit, it can't read the output)
p.WaitForExit(60000);
// read the exit code, close process
int returnCode = p.ExitCode;
p.Close();
// if 0 or 2, it worked so return path of pdf
if ((returnCode == 0) || (returnCode == 2))
return outputFolder + outputFilename;
else
throw new Exception(errorOutput);
//Response.ContentType = "application/pdf";
//Response.AddHeader("content-length", theData.Length.ToString());
//if (Request.QueryString["attachment"] != null)
// Response.AddHeader("content-disposition", "attachment; filename=ExampleSite.pdf");
//else
// Response.AddHeader("content-disposition", "inline; filename=ExampleSite.pdf");
//Response.BinaryWrite(theData);
//HttpContext.Current.ApplicationInstance.CompleteRequest();
}
catch (Exception exc)
{
throw new Exception("Problem generating PDF from HTML, URLs: " + urlsSeparatedBySpaces + ", outputFilename: " + outputFilenamePrefix, exc);
}
}
From above code the PDF is generating well.but I have two pages with the same URL for LogIn and Logout User.for example lets say www.xyz/pdf/brason .This same URL is used for LogIn and LogOut User but content will be different depending upon the User LogIn or Logout.
Now when I LogIn and try to generate the PDF using above code It always show me the content of Logout User Page.I am not sure how can i solve this issue.
I think if I understood correctly this is because wkhtmltopdf that is calling the page is not logged in. Wkhtmltopdf is kind of like creating a new incognito browser window without any login cookies/session so the page correctly thinks it's not logged in. You could maby check by debugging the request that the server gets when wkhtmltopdf calls it.
If this is the issue it can be difficult to solve. The solution depends on your login system and what you can do to go around the issue. If you can duplicate the login by using cookies you could maby set the login cookie yourself, see http://madalgo.au.dk/~jakobt/wkhtmltoxdoc/wkhtmltopdf_0.10.0_rc2-doc.html#Page%20Options for more info on how to set cookie.
Another option would be to first create a request from a system that returns the logged in HTML and then save that to a file/stream and feed that file/stream to wkhtmltopdf (I'm guessing you could do that using HttpContext.Current.Request or something, I don't know).
Another workaround would be to create a duplicate page of the logged in page that looks exactly like the logged in page but really isn't - this page would just be used to fool wkhtmltopdf. Something like www.xyz/pdf/brason?foolwkhtmltopdf=true and then use that by calling something like if(url.ToLower() == "www.xyz/pdf/brason") {url="www.xyz/pdf/brason?foolwkhtmltopdf=true"; }. This could be a security risk depending on what information is shown though.
Hope this helps!
i think you need to save the output of the page before you convert to html. Because this calls the url directly and you are not signed in when it calls it convert to pdf the response gotten for its request
i had the same problem trying to convert a webform to pdf but with the values filled so i saved the response as html and the gave wkhtmltopdf the saved path as parameter
Response.ContentType = "application/pdf";
Response.AddHeader("content-disposition", "attachment;filename=TestPage.pdf");
Response.Cache.SetCacheability(HttpCacheability.NoCache);
StringWriter sw = new StringWriter();
HtmlTextWriter hw = new HtmlTextWriter(sw);
this.Page.RenderControl(hw);
StringReader sr = new StringReader(sw.ToString());
string htmlpath =Server.MapPath("~/htmloutput.html");
if (File.Exists(htmlpath))
{
File.Delete(htmlpath);
}
File.Create(htmlpath).Dispose();
using (TextWriter tw = new StreamWriter(htmlpath))
{
tw.WriteLine(sw.ToString());
tw.Close();
}
string path = Server.MapPath("~/wkhtmltopdf-page.pdf");
PdfConvert.ConvertHtmlToPdf(new Codaxy.WkHtmlToPdf.PdfDocument
{
Url = htmlpath,
HeaderLeft = "[title]",
HeaderRight = "[date] [time]",
FooterCenter = "Page [page] of [topage]"
}, new PdfOutput
{
OutputFilePath = path
});
you can call this on a button click event. Only tested this on asp.net webforms. on asp.net mvc you need some other way to get the views html output
Related
I have Get Method which I am expecting to open a pdf file in a new browser tab, but its not happening - below is the code
public void GetDoc(int id)
{
string fileInfo = "ID=[" + id + "] ";
try
{
var file = this.DomainLogicUnitOfWork.UploadedDocumentManager.GetById(id);
fileInfo = "FILENAME=[" + file.FileName + "]";
Response.Clear();
Response.ContentType = file.FileContentType;
Response.AppendHeader("content-disposition", "attachment; filename=" + file.FileName);
Response.OutputStream.Write(file.DocumentImage, 0, file.DocumentImage.Length);
Response.Output.Flush();
Response.End();
}
catch (Exception ex)
{
LogHandler.LogError(4617, "Error Downloading Document " + fileInfo, ex);
throw ex;
}
}
My url is opening correctly: http://localhost:xcxcxcx/Upload/GetDoc?id=1088 and it gives a warning when click on the start of the browser address and one more thing is the Word and other documents are being downloaded fine - means they are working fine but problem is just with PDF files. Any suggestions or ideas -
thank you all friends.
enclosing within the double quotes resolved the problem like in this one: Response.AppendHeader("content-disposition", $"attachment; filename=\"{file.FileName}\"");
I want to export .frx report that designed by FastReport as an pdf or excel file on a c# web form application like code below:
public static bool ShowReport(string ReportFileName, DataTable ReportData, string DBObjectName, string ExportType, out string Message, params string[] AdditionalParams)
{
FastReport.Utils.Config.WebMode = true;
string ReportFile = HttpContext.Current.Server.MapPath(WPResources.ReportsRoot) + string.Format("{0}_{1}.frx", ReportFileName, ExportType.ToUpper());
FastReport.Report objReport = new FastReport.Report();
objReport.Load(ReportFile);
objReport.Dictionary.Connections.Clear();
System.Data.DataTable resultTable = new DataTable();
objReport.RegisterData(ReportData, DBObjectName);
objReport.GetDataSource(DBObjectName).Enabled = true;
int ParamsCount = AdditionalParams.Length;
if ((ParamsCount % 2) != 0)
ParamsCount--;
for (int i = 0; i < ParamsCount; i += 2)
{
var DynamicControl = (objReport.FindObject(AdditionalParams[i]) as FastReport.TextObject);
if (DynamicControl != null)
{
DynamicControl.Text = AdditionalParams[i + 1];
DynamicControl.Visible = !string.IsNullOrEmpty(AdditionalParams[i + 1]);
}
}
(objReport.FindObject("rptData") as FastReport.DataBand).DataSource = objReport.GetDataSource(DBObjectName);
string fileName = Path.GetFileNameWithoutExtension(ReportFile);
fileName += "_" + WPFarsiDate.Today.ToString().Replace("/", ".") + "_" +
DateTime.Now.Hour.ToString() + "." +
DateTime.Now.Minute.ToString();
if (ExportType == "Excel")
{
using (MemoryStream objMemoryStream = new MemoryStream())
{
objReport.Prepare(false);
FastReport.Export.OoXML.Excel2007Export objExcel2007Export = new FastReport.Export.OoXML.Excel2007Export();
objExcel2007Export.OpenAfterExport = false;
objExcel2007Export.Export(objReport, objMemoryStream);
byte[] buffer = objMemoryStream.ToArray();
HttpContext.Current.Response.ClearHeaders();
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.ContentType = "application/vnd.ms-excel";
HttpContext.Current.Response.AddHeader("Content-Disposition", string.Format("inline;filename={0}.xlsx", fileName));
HttpContext.Current.Response.BinaryWrite(buffer);
HttpContext.Current.Response.End();
}
}
else if (ExportType == "Pdf")
{
using (MemoryStream objMemoryStream = new MemoryStream())
{
objReport.Prepare(false);
FastReport.Export.Pdf.PDFExport objPDFExport = new FastReport.Export.Pdf.PDFExport();
objPDFExport.EmbeddingFonts = true;
objPDFExport.OpenAfterExport = false;
objPDFExport.Export(objReport, objMemoryStream);
byte[] buffer = objMemoryStream.ToArray();
HttpContext.Current.Response.ClearHeaders();
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.ContentType = "application/octet-stream";
HttpContext.Current.Response.AddHeader("Content-Disposition", string.Format("attachment;filename={0}.pdf", fileName));
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.BinaryWrite(buffer);
HttpContext.Current.Response.End();
}
}
Message = string.Empty;
return true;
}
When I export it to excel, that is no any matter and it will be done successfuly. But when I export it to pdf, I get this error:
Showing a modal dialog box or form when the application is not running
in UserInteractive mode is not a valid operation. Specify the
ServiceNotification or DefaultDesktopOnly style to display a
notification from a service application.
It should be noted that mentioned error just occurs in the main server and the job can be done successfully in localhost.
It would be very helpful if someone could explain solution for this problem.
After much effort, I find solution for the problem. Fonts used in .frx files weren't the windows/fonts folder. So I copied the metioned fonts there and it worked properly.
Did you tried debug it? Which line throws this error?
Did you see any dialog windows in desktop version? Try to avoid it.
I use fast report in one of my ASP.Net Web Forms projects and I see this exception when I try to export PDF. I have this tag in .aspx file:
<fastreport:webreport id="remainedLeave" runat="server"
Width="100%" Height="100%"></fastreport:webreport>
Adding this property to fast report tag solved my problem:
PdfEmbeddingFonts="false"
I have a flex program (AS3/Flash) that allows the user to create PNG images of portions of the stage and send them via email. This works swimmingly.
I want to take the same image and send it to the clipboard, but that does not work. So the next best thing is to allow them to send it to their browser, where they can save it to a file.
Here is the code that I am using to do that;
bmpPanelData.draw(uiPrintObject)
var baPanel:ByteArray = PNGEnc.encode(bmpPanelData);
// Clipboard.generalClipboard.clear();
// var bolClipboard:Boolean = Clipboard.generalClipboard.setData(ClipboardFormats.BITMAP_FORMAT, baPanel, true);
// trace('bolClipboard=' + bolClipboard);
var strFileName:String = strPrintObject;
var strFileExt:String = "png"
var variables:URLVariables = new URLVariables();
variables.mimeType = "application/octet-stream";
variables.fileExt = strFileExt;
baPanel.position = 0;
var strPanel:String = getBytes(baPanel);
// var strPanel:String = baPanel.readMultiByte(baPanel.bytesAvailable,"latin1");
variables.fileContents = escape(strPanel);
trace('strPanel.length=' + strPanel.length + ' baPanel.length=' + baPanel.length);
variables.disposition = "Attachment";
variables.fileName = strFileName;
var u:URLRequest = new URLRequest( RootDomain + "SendBinaryFile2.aspx");
u.data = variables;
u.method = "POST";
navigateToURL(u,"_blank");
}
catch (err:Error)
{
Alert.show("This Panel cannot be copied to the clipboard. \nSorry for the inconvenience \nError: " + err.errorID,"E-mail not premitted",Alert.OK)
}
(I left the clipboard stuff commented out in case someone knows how to do that. It is my understanding that you cannot send binary data to the clipboard from Flash, but it works in AIR.)
Since I could not find an AS3 method to convert a binary ByteArray to a string I wrote my own called getBytes. If you know of a method in AS3, please let me know.
private function getBytes(baArray:ByteArray):String
{
var strOut:String = "";
baArray.position = 0;
var intBASize:int = baArray.bytesAvailable;
for (var i:int = 0;i < intBASize;i++)
{
strOut += String.fromCharCode(baArray.readByte());
}
return strOut;
}
On the ASPX side I have a file called SendBinaryFile2.aspx that looks like this;
<%# Page Language="C#" validateRequest="false"%>
<script Runat="Server">
void Page_Load(Object sender, EventArgs e)
{
string fileExt = Request.Form["fileExt"];
string mimeType = Request.Form["mimeType"];
string disposition = Request.Form["disposition"];
string fileName = Request.Form["fileName"];
byte [] fileContents = Encoding.ASCII.GetBytes(HttpUtility.UrlDecode(Request.Form["fileContents"]));
Response.Buffer = true;
Response.Clear();
Response.AddHeader("Content-Length", fileContents.Length.ToString());
Response.ContentType = mimeType;
Response.AddHeader("Content-Disposition", disposition + "; filename=" + fileName + "." + fileExt);
Response.BinaryWrite(fileContents);
Response.Flush();
Response.Close();
Response.End();
}
</script>
The results is a file that looks a whole lot like a .PNG file, but is corrupt when it is opened. I have visually compared the file sent via email, and the one sent via this program using VIM, and they look similar, have roughly the same number of characters, begin/end with similar characters.
Help on any of the items defined above is greatly appreciated.
Try this for your getBytes function...
private function getBytes (baArray:ByteArray) : String
{
var strOut:String = ""; var strRead:String = "";
baArray.position = 0;
var intBASize:uint = baArray.length;
for (var i:int = 0; i < intBASize; i++)
{
strRead = baArray.readUnsignedByte().toString(16);
if(strRead.length < 2) { strRead = "0" + strRead; } //# do padding
strOut += strRead ;
}
return strOut.toUpperCase();
}
This should give you padded bytes. Consider x0FF3 becomes just xFF3 without the padding, later the other side could be assuming the bytes are really xFF30 leading to corrupt images.
I'd suggest you use Base64 encoding to transport your binary data. You already must have needed to use it for encoding your email attachment, anyways.
Actionscript:
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/utils/Base64Encoder.html
c#:
byte[] textAsBytes = System.Convert.FromBase64String(encodedText);
Also, if your SWF is running as standalone AIR (You wrote "Flex program"...), you can directly save files anywhere and give the user a "Save as..." prompt to do so.
Source to save from AIR:
var bmpd:BitmapData = new BitmapData(myWidth, myHeight, true, 0);
bmpd.draw(mySource);
var imgByteArray:ByteArray = new PNGEncoder().encode(bmpd);
var fl:File = File.desktopDirectory.resolvePath("myImage.png");
var fs:FileStream = new FileStream();
fs.open(fl, FileMode.WRITE);
fs.writeBytes(imgByteArray);
fs.close();
Having some trouble exporting to downloadable Excel content, using AngularJS & ASP.NET MVC. My end results is nothing happens.
Sample ASP.NET Controller method:
[HttpPost]
public ActionResult ExportToExcel(Model form)
{
var gv = new GridView();
gv.DataSource = _service.getSomeStuff(form);
gv.DataBind();
Response.ClearContent();
Response.Buffer = true;
Response.AddHeader("content-disposition", "attachment; filename=Stuff.xls");
Response.ContentType = "application/ms-excel";
Response.Charset = "";
var sw = new StringWriter();
var htw = new HtmlTextWriter(sw);
gv.RenderControl(htw);
Response.Output.Write(sw.ToString());
Response.Flush();
Response.End();
byte[] temp = System.Text.Encoding.UTF8.GetBytes(sw.ToString());
return File(temp, "application/ms-excel");
}
Angular Controller Method: -> triggered via ng-click handler
function exportToExcel() {
$http.post('/Controller/ExportToExcel/', vm.Model)
.success(function (data) {
})
.error(function (data) {
alerts.error(data);
});
}
View:
click me
Any suggestions of what I might be doing wrong?
I have done something like this, without the need for AJAX or any JS. Tweaking the Razor code is all that is required.
Secondly, my personal suggestion would be to not convert to Excel file at all. The reason being, the user is required to have Office on his local machine. It also means, should you upload your project to a website, that server machine will need Office installed in order to produce your excel file.
That being said, I would suggest just using a CSV file. If a user has Office installed, they would be able to use Excel to view the file like any spreadsheet.
Here is some code that will create a CSV called Export.csv from a dbset in your dbcontext, done using StringBuilder and Reflection.
public ActionResult Export()
{
StringBuilder str = new StringBuilder();
var tmp = db.Users.FirstOrDefault();
Type comp = tmp.GetType(); // get type
foreach (PropertyInfo prop in comp.GetProperties())
{
str.Append(prop.Name + ","); //set column names
}
str.Replace(",", "\n", str.Length - 1, 1);
foreach (object item in db.Users)
{
foreach (PropertyInfo prop in item.GetType().GetProperties())
{
try
{
string a = prop.GetValue(item, null).ToString();
str.Append(a + ",");
}
catch (NullReferenceException)
{
str.Append("null" + ","); //for nulls, append string with "null"
}
}
str.Replace(",", "\n", str.Length - 1, 1);
}
string csv = str.ToString();
return File(new System.Text.UTF8Encoding().GetBytes(csv), "text/csv", "Export.csv");
}
You can then access download the file with a link on your view like this:
click me
Hope this helps.
I have some code for sending a data result to the user as CSV.
This works fine with Excel 2013 but in Excel 2007, it won't split into columns, but rather as data inserted into only one column.
Is there a way of telling Excel how to split the text (it's separated by ; ) ?
Here is my code:
public async Task ExcelResultList(int id)
{
var asString = await Resolver.Resolve<IHandoutManager>().GetResultListAsStringAsync(id);
var handout = await Resolver.Resolve<IHandoutManager>().GetHandout(id);
var filename = string.Format("{0} registrations - {1:yyyy-MM-dd}.csv", handout.Name, DateTime.Now);
var contenttype = "application/csv";
Response.Clear();
Response.ContentType = contenttype;
Response.AddHeader("content-disposition", "attachment;filename=" + filename);
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.ContentEncoding = Encoding.Unicode;
Response.Write(asString);
Response.End();
}
To make sure that you are using the correct ListSeparator ("," or ";") use this
System.Globalization.CultureInfo.CurrentCulture.TextInfo.ListSeparator
But since you only have access to the server side, then you can include this javascript in any of your pages,
function getListSeparator() {
var list = ['a', 'b'], str;
if (list.toLocaleString) {
str = list.toLocaleString();
if (str.indexOf(';') > 0 && str.indexOf(',') == -1) {
return ';';
}
}
return ',';
}
The key is in the toLocaleString method that uses the system list separator of the client side
You could use JavaScript to get the list separator and set it in a cookie which you could then detect from your server to generate the file as needed
And also have you try changing the contenttype to
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
or
application/vnd.ms-excel