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");
Related
I'm testing how to upload to AWS using SDK with a sample .txt file from a web app. The file uploads to the Bucket, but the downloaded file from the bucket is just an empty Notepad document without the text from the original uploaded file. I'm new to working with streams, so I'm not sure what could be wrong here. Does anyone see why the data wouldn't be sent in the transfer request? Thanks in advance!
using (var client = new AmazonS3Client(Amazon.RegionEndpoint.USWest1))
{
//Save File to Bucket
using (FileStream txtFileStream = (FileStream)UploadedHttpFileBase.InputStream)
{
try
{
TransferUtility fileTransferUtility = new TransferUtility();
fileTransferUtility.Upload(txtFileStream, bucketLocation,
UploadedHttpFileBase.FileName);
}
catch (Exception e)
{
e.Message.ToString();
}
}
}
EDIT:
Both TransferUtility and PutObjectRequest/PutObjectResponse/AmazonS3Client.PutObject saved a blank text file. Then, after having some trouble instantiating a new FileStream, a MemoryStream used after resetting the starting position to zero still saved a blank text file. Any ideas?
New Code:
using (var client = new AmazonS3Client(Amazon.RegionEndpoint.USWest1))
{
Stream saveableStream = new MemoryStream();
using (Stream source = (Stream)UploadedHttpFileBase.InputStream)
{
source.Position = 0;
source.CopyTo(saveableStream);
}
//Save File to Bucket
try
{
PutObjectRequest request = new PutObjectRequest
{
BucketName = bucketLocation,
Key = UploadedHttpFileBase.FileName,
InputStream = saveableStream
};
PutObjectResponse response = client.PutObject(request);
}
catch (Exception e)
{
e.Message.ToString();
}
}
Most probably that TransferUtility doesn't work good with temporary upload files. Try to copy your input stream somewhere (e.g. into other not-so-temporary file, or even MemoryStream if you're sure it would not give you OutOfMemory at some point). Another thing is to get rid of TransferUtility and use low-level AmazonS3Client.PutObject with which you get finer control over Stream lifetime (do not forget that you'll need to implement some retrying as S3 API is prone to returning random temporary errors).
The answer had something to do with nesting, which is still a little beyond my understanding, and not because the code posted here was inherently wrong. This code came after an initial StreamReader which checked the first line of the text file to determine whether or not to save the file. After moving the code out from the while loop doing the ReadLines, the upload worked. Everything works as it's supposed to now that the validation is reorganized so that there's no need for the nested Stream or MemoryStream.
I have to serve large files (200-800MB) to the client from my controller. I tested FileStreamResult, but this class buffered the whole file in memory. This behavior is not good enough for my project.
Further i testest the approach from here: http://support.microsoft.com/kb/812406. Concerning the memory, this looks pretty good -but the files are not completly downloaded on the client (the original file is 210222 KB, the downloaded ones are 209551 to 209776). This means there is about 0.5 MB lost (which concequently causes the files to be broken).
Has somebody an idea? Whats the best way to do this anyway? Im grateful for everything.
Just for users in the future, the link pointed to the following code:
System.IO.Stream iStream = null;
// Buffer to read 10K bytes in chunk:
byte[] buffer = new Byte[10000];
// Length of the file:
int length;
// Total bytes to read:
long dataToRead;
// Identify the file to download including its path.
string filepath = "DownloadFileName";
// Identify the file name.
string filename = System.IO.Path.GetFileName(filepath);
try
{
// Open the file.
iStream = new System.IO.FileStream(filepath, System.IO.FileMode.Open,
System.IO.FileAccess.Read,System.IO.FileShare.Read);
// Total bytes to read:
dataToRead = iStream.Length;
Response.ContentType = "application/octet-stream";
Response.AddHeader("Content-Disposition", "attachment; filename=" + filename);
// Read the bytes.
while (dataToRead > 0)
{
// Verify that the client is connected.
if (Response.IsClientConnected)
{
// Read the data in buffer.
length = iStream.Read(buffer, 0, 10000);
// Write the data to the current output stream.
Response.OutputStream.Write(buffer, 0, length);
// Flush the data to the HTML output.
Response.Flush();
buffer= new Byte[10000];
dataToRead = dataToRead - length;
}
else
{
//prevent infinite loop if user disconnects
dataToRead = -1;
}
}
}
catch (Exception ex)
{
// Trap the error, if any.
Response.Write("Error : " + ex.Message);
}
finally
{
if (iStream != null)
{
//Close the file.
iStream.Close();
}
Response.Close();
}
Update
This is my action:
public DownloadResult TransferTest()
{
string fullFilePath = #"C:\ws\Test\Test\Templates\example.pdf";
return new DownloadResult(fullFilePath);
}
I simply call the action directly from my browser (http://xxx.xxx/Other/TransferTest).
The code basically looks sound - you are more-or-less correctly handling the return value from Read (if I was being picky, I would say check it for <=0, but this would not be an expected behavior since you probably have a lock on the file).
The only thing that occurs is: try adding a:
Response.OutputStream.Flush();
and perhaps:
Response.OutputStream.Close();
to make sure that the output stream is flushed.
I'm trying to convert a .db file to binary so I can stream it across a web server. I'm pretty new to C#. I've gotten as far as looking at code snippets online but I'm not really sure if the code below puts me on the right track. How I can write the data once I read it? Does BinaryReader automatically open up and read the entire file so I can then just write it out in binary format?
class Program
{
static void Main(string[] args)
{
using (FileStream fs = new FileStream("output.bin", FileMode.Create))
{
using (BinaryWriter bw = new BinaryWriter(fs))
{
long totalBytes = new System.IO.FileInfo("input.db").Length;
byte[] buffer = null;
BinaryReader binReader = new BinaryReader(File.Open("input.db", FileMode.Open));
}
}
}
}
Edit: Code to stream the database:
[WebGet(UriTemplate = "GetDatabase/{databaseName}")]
public Stream GetDatabase(string databaseName)
{
string fileName = "\\\\computer\\" + databaseName + ".db";
if (File.Exists(fileName))
{
FileStream stream = File.OpenRead(fileName);
if (WebOperationContext.Current != null)
{
WebOperationContext.Current.OutgoingResponse.ContentType = "binary/.bin";
}
return stream;
}
return null;
}
When I call my server, I get nothing back. When I use this same type of method for a content-type of image/.png, it works fine.
All the code you posted will actually do is copy the file input.db to the file output.bin. You could accomplish the same using File.Copy.
BinaryReader will just read in all of the bytes of the file. It is a suitable start to streaming the bytes to an output stream that expects binary data.
Once you have the bytes corresponding to your file, you can write them to the web server's response like this:
using (BinaryReader binReader = new BinaryReader(File.Open("input.db",
FileMode.Open)))
{
byte[] bytes = binReader.ReadBytes(int.MaxValue); // See note below
Response.BinaryWrite(bytes);
Response.Flush();
Response.Close();
Response.End();
}
Note: The code binReader.ReadBytes(int.MaxValue) is for demonstrating the concept only. Don't use it in production code as loading a large file can quickly lead to an OutOfMemoryException. Instead, you should read in the file in chunks, writing to the response stream in chunks.
See this answer for guidance on how to do that
https://stackoverflow.com/a/8613300/141172
In my .aspx page, I have download button which onclick download the .apk file.
When I run on my pc it works fine .apk file gets downloaded on my pc. But when I use my android phone go to that site and click download button it will start downloading but file click gives error There is a problem parsing the package.
Also actual file size is 604kb (while downloading from andorid phone gives 22kb)
The downloaded file(22kb) contain html content.
private void DownloadFile()
{
string getPath = "demo_Android/demoAndroid.apk";
System.IO.Stream iStream = null;
// Buffer to read 10K bytes in chunk:
byte[] buffer = new Byte[1024];
// Length of the file:
int length;
// Total bytes to read:
long dataToRead;
// Identify the file to download including its path.
string filepath = Server.MapPath(getPath);
// Identify the file name.
string filename = System.IO.Path.GetFileName(filepath);
try
{
// Open the file.
iStream = new System.IO.FileStream(filepath, System.IO.FileMode.Open,
System.IO.FileAccess.Read, System.IO.FileShare.Read);
// Total bytes to read:
dataToRead = iStream.Length;
Response.ContentType = "application/vnd.android.package-archive";
Response.AddHeader("Content-Disposition", "attachment; filename=" + filename);
// Read the bytes.
while (dataToRead > 0)
{
// Verify that the client is connected.
if (Response.IsClientConnected)
{
// Read the data in buffer.
length = iStream.Read(buffer, 0, 1024);
// Write the data to the current output stream.
Response.OutputStream.Write(buffer, 0, length);
// Flush the data to the HTML output.
Response.Flush();
buffer = new Byte[1024];
dataToRead = dataToRead - length;
}
else
{
//prevent infinite loop if user disconnects
dataToRead = -1;
}
}
}
catch (Exception ex)
{
// Trap the error, if any.
Response.Write("Error : " + ex.Message);
}
finally
{
if (iStream != null)
{
//Close the file.
iStream.Close();
}
Response.Close();
}
}
Heres how i fixed my problem
My Application is hosted under Window server 2008r2 having IIS 7
Step 1: In .aspx page add hyperlink set navigateurl as file path
<asp:HyperLink ID="lnkdwnload" runat="server" NavigateUrl="~/Application_Android/MyAndroidAppAame.apk">Download MyApp</asp:HyperLink>
Step 2: Web.config add mimeMap element under staticContent
<system.webServer>
<staticContent>
<mimeMap fileExtension=".apk" mimeType="application/vnd.android.package-archive"/>
</staticContent>
</system.webServer>
This could be the same problem I've also faced with Android's native browser. Thing is that the download action is being passed to the platform's download application (separate from the browser) which reloads the page and instead of the real APK, it downloads the aspx page.
Try downloading with Opera Mobile. If the problem goes away, it's most probably the same problem. Replacing the button with a standard hyperlink would be the simplest solution to this. Though it might not be an option if you need to have other logic there aswell instead of just downloading.
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