Stream a PDF to a web page failing - c#

I have a URL to a PDF and I want to serve up the PDF to my page viewer.
I can successfully (I think) retrieve the PDF file. Then when I do the Response.BinaryWrite() I get a "The file is damaged and could not be repaired" error from the adobe reader.
Here's the code I have:
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
{
byte[] output = DoWork("Http://localhost/test.pdf");
Response.Clear();
Response.ContentType = "application/pdf";
Response.AddHeader("content-disposition", "inline; filename=MyPDF.PDF");
Response.AddHeader("content-length", output.Length.ToString());
Response.BinaryWrite(output);
Response.End();
}
}
public byte[] DoWork(string requestUrl)
{
byte[] responseData;
HttpWebRequest req = null;
HttpWebResponse resp = null;
StreamReader strmReader = null;
try
{
req = (HttpWebRequest)WebRequest.Create(requestUrl);
using (resp = (HttpWebResponse)req.GetResponse())
{
byte[] buffer = new byte[resp.ContentLength];
BinaryReader reader = new BinaryReader(resp.GetResponseStream());
reader.Read(buffer, 0, buffer.Length);
responseData = buffer;
}
}
finally
{
if (req != null)
{
req = null;
}
if (resp != null)
{
resp.Close();
resp = null;
}
}
return responseData;
}

Apparently, I need to use ReadBytes() For some reason, when reading a PDF from a URL, You don't get all of the bytes that you requested.
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
{
byte[] output = DoWork("Http://localhost/test.pdf");
Response.Clear();
Response.ContentType = "application/pdf";
Response.AddHeader("content-disposition", "attachment");
Response.AddHeader("content-length", output.Length.ToString());
Response.BinaryWrite(output);
Response.End();
}
}
public byte[] DoWork(string requestUrl)
{
byte[] responseData;
HttpWebRequest req = null;
HttpWebResponse resp = null;
StreamReader strmReader = null;
try
{
req = (HttpWebRequest)WebRequest.Create(requestUrl);
using (resp = (HttpWebResponse)req.GetResponse())
{
byte[] buffer = new byte[resp.ContentLength];
using (BinaryReader reader = new BinaryReader(resp.GetResponseStream()))
{
buffer = reader.ReadBytes(buffer.Length);
reader.Close();
}
responseData = buffer;
}
}
finally
{
if (req != null)
{
req = null;
}
if (resp != null)
{
resp.Close();
resp = null;
}
}
return responseData;
}

Try saving the resulting file to your disk. Then open the file with a text editor. Maybe there are some errors in your script/source file.

You can also try to use FileStream the read the file
string strPath = Request.PhysicalApplicationPath
+ "\\document\\Test.pdf";
FileStream fStream = new FileStream
(strPath, FileMode.Open, FileAccess.Read);
StreamReader sReader = new StreamReader(fStream);

Try to flush the response after the binary write...
Response.BinaryWrite(output);
Response.Flush();
Response.End();
Alternatively, instead of inline, try to output the PDF as an attachment:
Response.AddHeader("Content-Disposition", "attachment;filename=MyPDF.PDF");

When I did this in Perl the other day (as a quick hack for our intranet), the crux of the script was:
binmode(STDOUT);
print "Content-type: application/pdf\n\n";
binmode(FILE);
print <FILE>;
close(FILE);
The key points being to make sure that the input and output streams are in binary mode, i.e. as you've found, the PDF needs to be interpreted as binary data throughout the chain.

You might be able to simplify your code quite a bit by using the WebClient class
Here's the MSDN documentation. Its not as cumbersome as the lower level HttpWebRequest class.

Related

Not able to download and parallelly open a file object stored in server in asp.net

I have tried to download and opened a file object stored in Server, but not able to open the file post download. Please find the sample code I am trying as below. I have used Content-Disposition to inline, but still it is not working as mentioned in other solution to this problem. It just downloads, but don't open. Any help please on this?
protected void Page_Load(object sender, EventArgs e)
{
string filePath = this.Server.MapPath("~/Scripts/48A4-4972-AEBE-8E7C11AE64AF");
string fileName = "crma.jpg";
FileStream stream = null;
HttpResponse response = HttpContext.Current.Response;
long dataToRead;
try
{
stream = new FileStream(filePath, FileMode.Open);
dataToRead = stream.Length;
response.ClearContent();
response.AddHeader("Content-Disposition", "inline; filename=" + "\"" + fileName + "\"");
response.AddHeader("Content-Length", dataToRead.ToString());
response.ContentType = "application/jpg";
byte[] buffer = new Byte[10000];
while (dataToRead > 0)
{
if (response.IsClientConnected)
{
int length = stream.Read(buffer, 0, 10000);
response.OutputStream.Write(buffer, 0, length);
response.Flush();
buffer = new Byte[10000];
dataToRead = dataToRead - length;
}
else
{
dataToRead = -1;
}
}
}
finally
{
if (stream != null)
stream.Close();
response.End();
response.Close();
}
}

I need to append multiple filestreams to the same pdf file

I have a function that converts a ZPL(Zebra Label) into a PDF format and saves the file. What I'm trying to do is instead of overwriting the file each time, I would like to append the filestream to the file (if it exists), write new (if not exists).
I've tried setting a new filestream with filemode.append, that did not seem to make a difference.
private static void SaveLabel(string label, string labelDir, string caseNumber)
{
var zpl = Encoding.UTF8.GetBytes(label);
var fileName = $#"{labelDir}\{caseNumber}.pdf";
// adjust print density (8dpm), label width (4 inches), label height (6 inches), and label index (0) as necessary
var request = (HttpWebRequest)WebRequest.Create("http://api.labelary.com/v1/printers/8dpmm/labels/4x6/0/");
request.Method = "POST";
request.Accept = "application/pdf"; // omit this line to get PNG images back
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = zpl.Length;
var requestStream = request.GetRequestStream();
requestStream.Write(zpl, 0, zpl.Length);
requestStream.Close();
try
{
var response = (HttpWebResponse)request.GetResponse();
var responseStream = response.GetResponseStream();
if (!File.Exists(fileName))
File.Create(fileName);
using (var fileStream = File.Open(fileName, FileMode.Append))
{
responseStream?.CopyTo(fileStream);
responseStream?.Close();
fileStream.Close();
}
}
catch (WebException e)
{
Console.WriteLine(#"Error: {0}", e.Status);
}
}
I first check to see if the file existed (meaning there was going to be more than one label for the shipment). If not, process as normal. If yes, then read that file into a new pdf file. Then read the contents of the current response stream into a 2nd new pdf file.
I then delete the destination file freeing the name for the new combined pdf. I then use the suggested link to PDFSharp and combine the pages and save as the original file name. This will enable a continuous appending of the file regardless of how many package labels are generated.
private static void SaveLabel(string label, string labelDir, string caseNumber)
{
var zpl = Encoding.UTF8.GetBytes(label);
var destFileName = $#"{labelDir}\{caseNumber}.pdf";
// adjust print density (8dpm), label width (4 inches), label height (6 inches), and label index (0) as necessary
var request = (HttpWebRequest)WebRequest.Create("http://api.labelary.com/v1/printers/8dpmm/labels/4x6/0/");
request.Method = "POST";
request.Accept = "application/pdf"; // omit this line to get PNG images back
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = zpl.Length;
var requestStream = request.GetRequestStream();
requestStream.Write(zpl, 0, zpl.Length);
requestStream.Close();
try
{
var response = (HttpWebResponse)request.GetResponse();
var responseStream = response.GetResponseStream();
if (File.Exists(destFileName))
{
var oldStream = File.OpenRead(destFileName);
var oldFileName = $#"{labelDir}\{caseNumber}-1.pdf";
using (var fileStream = File.Open(oldFileName, FileMode.Create))
{
oldStream.CopyTo(fileStream);
oldStream.Close();
fileStream.Close();
}
var newFileName = $#"{labelDir}\{caseNumber}-2.pdf";
using (var fileStream = File.Open(newFileName, FileMode.Create))
{
responseStream?.CopyTo(fileStream);
responseStream?.Close();
fileStream.Close();
}
File.Delete(destFileName);
using (var pdfOne = PdfReader.Open(oldFileName, PdfDocumentOpenMode.Import))
{
using (var pdfTwo = PdfReader.Open(newFileName, PdfDocumentOpenMode.Import))
{
using (var outPdf = new PdfDocument())
{
CopyPages(pdfOne, outPdf);
CopyPages(pdfTwo, outPdf);
outPdf.Save(destFileName);
}
}
}
File.Delete(oldFileName);
File.Delete(newFileName);
}
else
{
using (var fileStream = File.Open(destFileName, FileMode.Create))
{
responseStream?.CopyTo(fileStream);
responseStream?.Close();
fileStream.Close();
}
}
}
catch (WebException e)
{
Console.WriteLine(#"Error: {0}", e.Status);
}
}

Unable to get full image from server

I have a C# windows form application which downloads file from a url(asp.net application) but it is not returning full image lets say image is of 780kb the file that windows form creates is 381 bytes exactly.
I am not able to figure out the issue. Please help.
The code i am using for download is:
public bool getFileFromURL(string url, string filename)
{
long contentLength = 0;
Stream stream = null;
try
{
WebRequest req = WebRequest.Create(url);
WebResponse response = req.GetResponse();
stream = response.GetResponseStream();
contentLength = response.ContentLength;
// Transfer the file
byte[] buffer = new byte[10 * 1024]; // 50KB at a time
int numBytesRead = 0;
long totalBytesRead = 0;
using (FileStream fileStream = new FileStream(filename, FileMode.Create))
{
using (BinaryWriter fileWriter = new BinaryWriter(fileStream))
{
while (stream.CanRead)
{
numBytesRead = stream.Read(buffer, 0, buffer.Length);
if (numBytesRead == 0) break;
totalBytesRead += numBytesRead;
fileWriter.Write(buffer, 0, numBytesRead);
}
fileWriter.Close();
}
fileStream.Close();
}
stream.Close();
response.Close();
req.Abort();
return true;
}
catch (Exception)
{
return false;
}
}
This is my asp.net app code:
using (PortalEntities db = new PortalEntities())
{
PortalModel.Command command = db.Commands.SingleOrDefault(c => c.id == id);
var filePath = Server.MapPath("~/Uploads/"+command.arguments);
if (!File.Exists(filePath))
return;
var fileInfo = new System.IO.FileInfo(filePath);
Response.ContentType = "image/jpg";
Response.AddHeader("Content-Disposition", String.Format("attachment;filename=\"{0}\"", filePath));
Response.AddHeader("Content-Length", fileInfo.Length.ToString());
Response.WriteFile(filePath);
Response.End();
}
That's an awful lot of code to write some bytes out to a file from a web response. How about something like this (.NET 4+):
public static bool GetFileFromURL(string url, string filename)
{
try
{
var req = WebRequest.Create(url);
using (Stream output = File.OpenWrite(filename))
using (WebResponse res = req.GetResponse())
using (Stream s = res.GetResponseStream())
s.CopyTo(output);
return true;
}
catch
{
return false;
}
}
You can download image in more elegant way, it was discussed before here Unable to locate FromStream in Image class
And use File.WriteAllBytes Method to save the byte array as a file, more info at
http://msdn.microsoft.com/en-us/library/system.io.file.writeallbytes(v=vs.110).aspx
So all your client code can be replaced with
public void getFileFromURL(string url, string filename)
{
using (var webClient = new WebClient())
{
File.WriteAllBytes(filename,webClient.DownloadData(url));
}
}
Dude, why are you not using WebClient.DownloadFileAsync?
private void DownloadFile(string url, string path)
{
using (var client = new System.Net.WebClient())
{
client.DownloadFileAsync(new Uri(url), path);
}
}
That's pretty much it, but this method can't download over 2GB. But i don't think the image is that big xD.
Hope it helps!

Download and show an image from a URL in background

How to download & show an image from a URL using asp.net
e.g. I have a page ShowImage.aspx
When I call this page it should show image(from Response Stream) from external URL
https://appharbor.com/assets/images/stackoverflow-logo.png
with Response.ContentType = "Image/png"
SOLVED ON MY OWN
protected void Page_Load(object sender, EventArgs e)
{
WebRequest req = WebRequest.Create("https://appharbor.com/assets/images/stackoverflow-logo.png");
WebResponse response = req.GetResponse();
Stream stream = response.GetResponseStream();
Byte[] buffer = null;
Response.Clear();
Response.ContentType = "image/png";
Response.AddHeader("Content-Length", response.ContentLength.ToString());
int bytesRead = 0;
do
{
buffer = new Byte[4096];
bytesRead = stream.Read(buffer, 0, buffer.Length);
if (bytesRead > 0)
{
Response.OutputStream.Write(buffer,0,bytesRead);
}
} while (bytesRead > 0);
Response.End();
}
REF: http://forums.asp.net/t/1401931.aspx/1
You can simply use the Image.ImageUrl property of Image control
<asp:Image id="img1" runat="server" ImageUrl="https://appharbor.com/assets/images/stackoverflow-logo.png" />
If you want to set Image url from server side (code behind)
img1.ImageUrl = "http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.image.imageurl.aspx";
If you use WebRequest to get the Image string from url.
WebRequest req = WebRequest.Create("https://appharbor.com/assets/images/stackoverflow-logo.png");
WebResponse response = req.GetResponse();
Stream stream = response.GetResponseStream();
System.Drawing.Image image = System.Drawing.Image.FromStream(stream);
using (MemoryStream ms = new MemoryStream())
{
image.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
ms.WriteTo(Response.OutputStream);
}
public class Service1 : IService1
{
public Stream GetImage()
{
WebOperationContext.Current.OutgoingResponse.ContentType = "image/jpeg";
using(WebClient Client = new WebClient())
{
using(StreamReader Reader = new StreamReader(Client.OpenRead("FILE URL")))
{
try
{
string Contents = Reader.ReadToEnd();
Reader.Close();
return Contents;
}
catch
{
return string.Empty;
}
}
}
}
}

To download a zipped file from FTP

I am trying to do this using C#(Winforms).
The code I am using is giving me a string as an output, but I need to have a zipped file.
I am using the following code
try
{
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(
"ftp:SITENAME/FILENAME.zip");
request.Method = WebRequestMethods.Ftp.DownloadFile;
// This example assumes the FTP site uses anonymous logon.
request.Credentials = new NetworkCredential("", "");
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
Stream responseStream = response.GetResponseStream();
StreamReader reader = new StreamReader(responseStream);
//StreamWriter writer = new StreamWriter(responseStream);
MessageBox.Show(reader.ReadtoEnd);
MessageBox.Show("Download Complete, status {0}" + response.StatusCode);
reader.Close();
response.Close();
}
catch (NotSupportedException ne)
{
MessageBox.Show(ne.Message);
}
I have an idea that I have to use Open source library from SharpZipLib to convert this string to a zipped file. But,I cannot find any sample code to show me how to do that.
I would really appreciate if someone can guide me through the process.
Thanks,
Sidhanshu
This might do just that.
using ICSharpCode.SharpZipLib.BZip2;
public static string Unzip(byte[] compressedbytes)
{
string result;
MemoryStream m_msBZip2 = null;
BZip2InputStream m_isBZip2 = null;
m_msBZip2 = new MemoryStream(compressedbytes);
// read final uncompressed string size stored in first 4 bytes
using (BinaryReader reader = new BinaryReader(m_msBZip2, System.Text.Encoding.ASCII))
{
Int32 size = reader.ReadInt32();
m_isBZip2 = new BZip2InputStream(m_msBZip2);
byte[] bytesUncompressed = new byte[size];
m_isBZip2.Read(bytesUncompressed, 0, bytesUncompressed.Length);
m_isBZip2.Close();
m_msBZip2.Close();
result = Encoding.ASCII.GetString(bytesUncompressed, 0, bytesUncompressed.Length);
reader.Close();
}
return result;
}
public static byte[] Zip(string sBuffer)
{
byte[] result;
using (MemoryStream m_msBZip2 = new MemoryStream())
{
Int32 size = sBuffer.Length;
// Prepend the compressed data with the length of the uncompressed data (firs 4 bytes)
using (BinaryWriter writer = new BinaryWriter(m_msBZip2, System.Text.Encoding.ASCII))
{
writer.Write(size);
using (BZip2OutputStream m_osBZip2 = new BZip2OutputStream(m_msBZip2))
{
m_osBZip2.Write(Encoding.ASCII.GetBytes(sBuffer), 0, sBuffer.Length);
m_osBZip2.Close();
}
writer.Close();
result = m_msBZip2.ToArray();
m_msBZip2.Close();
}
}
return result;
}

Categories