I'm trying to start downloading files from server, now just with some hardcoded values for files which exists but for some reason the download does not start and no error is thrown.
This is the code I have:
public void ProcessRequest(HttpContext context)
{
string destPath = context.Server.MapPath("~/Attachments/cover.txt");
// Check to see if file exist
FileInfo fi = new FileInfo(destPath);
if (fi.Exists)
{
HttpContext.Current.Response.ClearHeaders();
HttpContext.Current.Response.ClearContent();
HttpContext.Current.Response.AppendHeader("Content-Length", fi.Length.ToString());
HttpContext.Current.Response.ContentType = "application/octet-stream";
HttpContext.Current.Response.AppendHeader("Content-Disposition", "attachment; filename=" + "cover.txt");
HttpContext.Current.Response.BinaryWrite(ReadByteArryFromFile(destPath));
HttpContext.Current.Response.End();
}
}
public bool IsReusable
{
get
{
return false;
}
}
private byte[] ReadByteArryFromFile(string destPath)
{
byte[] buff = null;
FileStream fs = new FileStream(destPath, FileMode.Open, FileAccess.Read);
BinaryReader br = new BinaryReader(fs);
long numBytes = new FileInfo(destPath).Length;
buff = br.ReadBytes((int)numBytes);
return buff;
}
I'm stepping in the code and no problem is occurring but as well no file download popup is shown in the browser.
Do you see anything wrong?
I believe the issue your having is that your calling HttpContext.Current. Since your utilizing a Generic Handler File I believe you'll want to utilize the context parameter being passed to your method signature. An example would be:
public void ProcessRequest (HttpContext context)
{
// Build Document and Zip:
BuildAndZipDocument();
// Context:
context.Response.ContentType = "application/zip";
context.Response.AddHeader("content-disposition", "filename="Commodity.zip");
zip.Save(context.Response.OutputStream);
// Close:
context.Response.End();
}
I believe if you utilize context, rather than HttpContext.Current it will resolve your issue.
NEVER use "application/zip" in your Content-Type header for a ZIP file. NEVER! Confirmed bug is in IE6 which will corrupt the download.
If you want the most universal behavior for a binary file across the most browsers past and present ALWAYS use "application/octet-stream" just like you see it used everywhere else!!
header('Content-Type: application/octet-stream');
This overcomes the IE6 bug, assuming you care. Nonetheless, you achieve nothing by switching from application/octet-stream to application/zip, so you might as well stop wasting your time on that one and keep it application/octet-stream.
Related
I get a request with which I create a file and return it to the client.
After the file is sent I want it deleted.
Since I get many request, files are big and memory is scarce, I don't want to buffer it in memory to send it.
The only method I got to work without buffering the whole file in memory was:
Response.TransmitFile(filepath)
The problem with this is that it does it asynchronously, so if I delete it after that call the file download is interrupted.
I tried calling Flush, adding the delete on a finally block but neither of those worked. I thought of inheriting HttpResponse to try modify TransmitFile, but it's a sealed class. I tried to use HttpResponse.ClientDisconnectedToken but either I don't understand how to use it correctly or it isn't working in this case.
How can I achieve this? Is there a better method than calling HttpResponse's TransmitFile? Always taking into account that this is an API, files can't be broken into different requests and that it doesn't load the full file in memory.
I'm not sure if it could help somehow, but my controller is inheriting from AbpApiController.
You create the file in a temp folder, just create a job to remove all files based on date/time. Maybe give the user 4 hours to download the file.
An implementation of TransmitFileWithLimit, It can be improve in many ways, but it works
Extension for HttpResponse
public static class HttpResponseExtensions
{
public static void TransmitFileWithLimit(this HttpResponse response, string path, int limit)
{
var buffer = new byte[limit];
var offset = 0;
response.ClearContent();
response.Clear();
response.ContentType = "text/plain";
using (var fileStream = File.OpenRead(path))
{
var lengthStream = fileStream.Length;
while (offset < lengthStream)
{
var lengthBytes = fileStream.Read(buffer, 0, limit);
var chars = System.Text.Encoding.ASCII.GetString(buffer, 0, lengthBytes).ToCharArray();
response.Write(chars, 0, lengthBytes);
offset += lengthBytes;
}
}
response.Flush();
response.End();
}
}
Inside Controller
public void Get()
{
var path = #"C:\temporal\bigfile.mp4";
var response = HttpContext.Current.Response;
response.ClearContent();
response.Clear();
response.AddHeader("Content-Disposition", "inline; filename=" + HttpUtility.UrlPathEncode(path));
response.ContentType = "text/plain";
response.AddHeader("Content-Length", new FileInfo(path).Length.ToString());
response.Flush();
HttpContext.Current.ApplicationInstance.CompleteRequest();
TransmitFileWithLimit(path, 10000);
File.Delete(path);
}
What you can do is to create a byte array from your file and then delete the file.
So, once it is created, you store it in memory, then you delete the file and return the byte array.
Check this answer to see an example.
I hope this helps.
So here are the details:
Firefox: update 12
AdobeReader: 11
Input: Convert.FromBase64String(string)=> byte[]
Task: to display the pdf within the browser
PDF is stored in a database.
I've read and tried a lot of possible solutions and fixes for this error. But I got no joy.
Is it possible to know if the converted string to byte[] is corrupted? And is it possible for the value being converted to byte[] to be damaged in the process?
The value of the pdfFile, data type byte[], is from a web service.
Here is the generic handler that I made:
public partial class ProcessPDFRequest : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
try
byte[] currentBillPDF = proxy.GetPdf(refNum, date);
using (MemoryStream ms = new MemoryStream(currentBillPDF))
{
context.Response.Clear();
context.Response.ContentType = "application/pdf";
if(isInline!="true")
context.Response.AddHeader("content-disposition", "attachment;filename=PDF_CurrentBill.pdf");
else
context.Response.AddHeader("content-disposition", "inline;filename=PDF_CurrentBill.pdf");
context.Response.Buffer = true;
ms.WriteTo(context.Response.OutputStream);
context.Response.End(); ;
}
EDIT
I use context.Response.Flush(); context.Response.End();
PDF was successfully displayed when I created another web application. However when I used the converted string to byte[] in the original solution, the error stated in the title is persisting. I already checked the bytes and compared it in notepad, both them showed %PDF-
Is there something I'm missing? the original solution is a sharepoint web application.
I am using ZipArchive with in a handler to serve to a user using memory stream and a web handler. Locally this was working until I uploaded the application to a live site.
Here is my code.
using (ZipArchive newArchive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true))
{
newArchive.CreateEntryFromFile(fileName, Path.GetFileName(fileName));
if (File.Exists(acRefFile))
{
newArchive.CreateEntryFromFile(acRefFile,
newACRefName + Path.GetExtension(acRefFile));
}
else
{
SystemLogManager sysLogMgr = new SystemLogManager();
sysLogMgr.AddErrorMessage(acRefFile, "File not found");
}
if (File.Exists(exRefFile))
{
newArchive.CreateEntryFromFile(exRefFile,
newExRefName + Path.GetExtension(exRefFile));
}
else
{
SystemLogManager sysLogMgr = new SystemLogManager();
sysLogMgr.AddErrorMessage(exRefFile, "File Not Found");
}
if (File.Exists(exRef2File))
{
newArchive.CreateEntryFromFile(exRef2File,
newExRef2Name + Path.GetExtension(exRef2File));
}
}
memoryStream.Position = 0;
byte[] bytes = memoryStream.GetBuffer();
context.Response.Buffer = true;
context.Response.Clear();
context.Response.ContentType = "application/zip";
context.Response.AddHeader("content-disposition",
string.Format("attachment; filename =app_{0}_{1}.zip", appForm.Cand_sno,
appForm.App_year));
context.Response.BinaryWrite(bytes.ToArray());
context.Response.Flush();
And the following image shows the downloaded zip file and the error generated.
So is there anything in code that could be wrong or something I could try server side?
Update 1:
Based on the comments received I tried adding the zip file directly onto the server. Same issue occurs as in the zip is 'corrupted'.
Update 2:
Further investigations I have now discovered that the zip file opens up when using 7zip but not standard windows extract. When right click extract all the message states the zip is empty.
Thanks
So the fix for this question was simply to change the byte[] bytes = MemoryStream.GetBuffer(); to byte[] bytes = MemoryStream.ToArray(); What this does is only get the used bytes not the extra bytes the buffer adds.
I use ZipFile class and the result is never corrupted.
Can you try this?
ZipFile.CreateFromDirectory("C:\somefolder", "C:\someotherfolder\somefile.zip");
The RedirectToAction does not display the View.
// Go populate and display PDF using XML file
DoPDF(stXML);
}
UpDateDropDown(model);
return RedirectToAction("ReportsSelection", "Reports");
Rendering Code:
private void DoPDF(String stXML)
{
string filename = string.Concat(Guid.NewGuid().ToString(), ".pdf");
PdfReader reader = new PdfReader(new RandomAccessFileOrArray(Request.MapPath(_NFCPage._NFReference.FM_NOFEAR_PDF)), null);
// Create the iTextSharp document
// Set the document to write to memory
using (MemoryStream memStream = new MemoryStream())
{
PdfStamper ps = new PdfStamper(reader, memStream);
// Populate the PDF with values in the XML file
AcroFields af = ps.AcroFields;
ParserXML(stXML, af);
ps.FormFlattening = false;
ps.Writer.CloseStream = false;
ps.Close();
byte[] buf = new byte[memStream.Position];
memStream.Position = 0;
memStream.Read(buf, 0, buf.Length);
// Set the appropriate ContentType
Response.ContentType = "Application/pdf";
// Get the physical path to the file
Response.AddHeader("Content-disposition", string.Format("attachment; filename={0};", filename));
// Write the file directly to the HTTP content output stream.
Response.Buffer = true;
Response.Clear();
Response.BinaryWrite(memStream.GetBuffer()); //Comment out to work
Response.End(); //Comment out to work
}
}
I have noticed that if I remove the last two lines in the DoPDF routine that it does display the view.
Response.End() will cause the server to send the HTTP response. Your browser at that point will consider the request completed and the redirect won't happen. Can you provide more context on what you're trying to accomplish? Then we can get a better idea of how to help you.
Edit: nvm, you have a Response.End() call there, that will end execution of the request and your redirect will obviously not work. If you're trying to flush the stream then you need to do Response.Flush() instead.
Don't handle files downloads in MVC, as you can see, it can cause problems...
return File(memStream, "Application/pdf", filename);
Will do everything for you.
MSDN
I'm trying to create a method which continually streams a zip file as a user downloads it (so that there is no wasted streaming)
I added a thread.sleep to simulate latency
public override void ExecuteResult(ControllerContext context) {
HttpResponseBase response = context.HttpContext.Response;
response.Clear();
response.ClearContent();
response.ClearHeaders();
response.Cookies.Clear();
response.ContentType = ContentType;
response.ContentEncoding = Encoding.Default;
response.AddHeader("Content-Type", ContentType);
context.HttpContext.Response.AddHeader("Content-Disposition",
String.Format("attachment; filename={0}",
this.DownloadName));
int ind = 0;
using (ZipOutputStream zipOStream =
new ZipOutputStream(context.HttpContext.Response.OutputStream))
{
foreach (var file in FilesToZip)
{
ZipEntry entry = new ZipEntry(FilesToZipNames[ind++]);
zipOStream.PutNextEntry(entry);
Thread.Sleep(1000);
zipOStream.Write(file, 0, file.Length);
zipOStream.Flush();
}
zipOStream.Finish();
}
response.OutputStream.Flush();
}
It seems like the zip will not start streaming until all the files are files are zipped. Is there a way to stream continuously? Maybe with a different library?
Assuming the zip format is partial to streaming, your problem is that your response is being buffered by default. If you set HttpResponseBase.BufferOutput to false, it should start streaming immediately.
I think you might need to be flushing the outputstream rather than the zipostream to see any output to http. So response.OutputStream.Flush() would appear in your loop in that case. Not sure if it will actually solver your problem though.