Upload handler with zip files and rar files - c#

I am using html input file to upload the files. Everything is working fine except in the case of .Zip or .rar. I am checking posted file in generic handler like:
HttpPostedFile PostedFile = context.Request.Files[0];
if (!(PostedFile == null))
{
//do processing..
}
I tried image files, pdf, doc, even sql query files. Every type is uploading well, but with the case of .rar or .zip files I am not getting posted file into ashx handler. I mean every time I get an object reference not set to an instance of an object error.
I wonder how could I can post the .rar files or .zip files to handler. I am appending data in client side using form data like:
var form = $("#form1")[0];
var formdata = new FormData(form);
formdata.append('Data', JSON.stringify({ objEnt: args }));

Check if you get the file contents in the context.Request.InputStream. If yes then you can use following code:
if (context.Request.InputStream != null && context.Request.InputStream.Length > 0)
{
System.IO.Stream fileContent = context.Request.InputStream;
System.IO.FileStream fileStream = System.IO.File.Create(Server.MapPath("~/") + fileName);
fileContent.Seek(0, System.IO.SeekOrigin.Begin);
fileContent.CopyTo(fileStream);
}

Related

Why is my zip file not showing any contents?

I've created a zip file method in my web api which returns a zip file to the front end (Angular / typescript) that should download a zip file in the browser. The issue I have is the file shows it has data by the number of kbs it has but on trying to extract the files it says it's empty. From a bit of research this is most likely down to the file being corrupt, but I want to know where I can find this is going wrong. Here's my code:
WebApi:
I won't show the controller as it basically just takes the inputs and passes them to the method. The DownloadFileResults passed in basically have a byte[] in the File property.
public FileContentResult CreateZipFile(IEnumerable<DownloadFileResult> files)
{
using (var compressedFileStream = new MemoryStream())
{
using (var zipArchive = new ZipArchive(compressedFileStream, ZipArchiveMode.Update))
{
foreach (var file in files)
{
var zipEntry = zipArchive.CreateEntry(file.FileName);
using (var entryStream = zipEntry.Open())
{
entryStream.Write(file.File, 0, file.File.Length);
}
}
}
return new FileContentResult(compressedFileStream.ToArray(), "application/zip");
}
}
This appears to work in that it generates a result with data. Here's my front end code:
let fileData = this._filePaths;
this._fileStorageProxy.downloadFile(Object.entries(fileData).map(([key, val]) => val), this._pId).subscribe(result => {
let data = result.data.fileContents;
const blob = new Blob([data], {
type: 'application/zip'
});
const url = window.URL.createObjectURL(blob);
window.open(url);
});
The front end code then displays me a zip file being downloaded, which as I say appears to have data due to it's size, but I can't extract it.
Update
I tried writing the compressedFileStream to a file on my local and I can see that it creates a zip file and I can extract the files within it. This leads me to believe it's something wrong with the front end, or at least with what the front end code is receiving.
2nd Update
Ok, turns out this is specific to how we do things here. The request goes through platform, but for downloads it can only handle a BinaryTransferObject and I needed to hit a different end point. So with a tweak to no longer returning a FileContentResult and hitting the right end point and making the url simply an ahref it's now working.

Open PDF file with Save As option in asp.net webform

I have list of PDF files on website (asp.net webforms). i want to open them with Save As option rather than it downlaods directly.
I tried to add download property to the link which didn't work. only was around seems to be HTTPHandler for *.pdf request.
I saw a piece of code for MVC based example here
return new FileStreamResult(stream, "application/pdf")
{
FileDownloadName = "file.pdf"
};
How can i convert this to HTTPHandler in as.net webform so that it open pdf files with Save As option.
I want to do it in a way so that when ever user click on any pdf file at that time Handler should come into action.
OR
I can create another file handlePDF.aspx and write code there also and will change link of pdf file to below
File One
If what you are trying to do is when they click on the file download link it pops up with save as or open dialog box, this is to do with the user's browser configuration. In the case of PDF's i believe Firefox has open in tab as the default option. If you try to push the file as a file stream it will more than likely just load it in a new tab as well.
tl;dr: Client side issue
You're on the right track. Serving PDF files are usually handled by an HttpHandler. That is, unless they can be served straight from the file system by the StaticHandler...
The key thing that is needed in order for the browser to raise the "Open or save" dialog is the Content-Disposition header in the response.
Here is an (untested) implementation that should get you on the right track:
public void ProcessRequest(HttpContext context)
{
string fileName = context.Request.QueryString["file"];
if(fileName == null || fileName == "")
{
throw new ArgumentException("The file argument cannot be null or empty");
}
// fetch file here from db/filesystem/other storage
byte[] fileBytes = LoadFileBytes(fileName);
context.Response.AddHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
context.Response.ContentType = "application/pdf";
context.Response.BinaryWrite(fileBytes);
}
If you want to avoid buffering the whole file in memory, this might also work (requires .Net 4.0 for the CopyTo method on the stream):
public void ProcessRequest(HttpContext context)
{
string fileName = context.Request.QueryString["file"];
if(fileName == null || fileName == "")
{
throw new ArgumentException("The file argument cannot be null or empty");
}
// fetch file stream from db/filesystem/other storage
Stream fileStream = GetFileStream(fileName);
context.Response.AddHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
context.Response.ContentType = "application/pdf";
fileStream.CopyTo(context.Response.OutputStream);
}

OutOfMemory exception when trying to download multiple files as a Zip file using Ionic.Zip dll

This is my working code that I used to download multiple files as a zip file using Ionic.Zip dll. File contents is stored in a SQL database. This program works if I try to download 1-2 files at a time, but throws an OutOfMemory exception if I try to download multiple files as some of the files may very large.
Exception occurs when it's trying to write in to outputStream.
How can I improve this code to download multiple files or is there a better way to download multiple files one by one rather than zipping them to a one large file?
Code:
public ActionResult DownloadMultipleFiles()
{
string connectionString = "MY DB CONNECTIOBN STRING";
List<Document> documents = new List<Document>();
var query = "MY LIST OF FILES - FILE METADA DATA LIKE FILEID, FILENAME";
documents = query.Query<Document>(connectionString1).ToList();
List<Document> DOCS = documents.GetRange(0, 50); // 50 FILES
Response.Clear();
var outputStream = new MemoryStream();
using (var zip = new ZipFile())
{
foreach (var doc in DOCS)
{
Stream stream = new MemoryStream();
byte[] content = GetFileContent(doc.FileContentId); // This method returns file content
stream.Write(content, 0, content.Length);
zip.UseZip64WhenSaving = Zip64Option.AsNecessary // edited
zip.AddEntry(doc.FileName, content);
}
zip.Save(outputStream);
}
return File(outputStream, "application/zip", "allFiles.zip");
}
Download the files to disc instead of to memory, then use Ionic to zip them from disc. This means you don't need to have all the files in memory at once.

Create an Excel file on server and send to a browser

I'm using EPPlus to create an excel file on the server. The problem is that I wan't the file to be saved on the clients harddrive and when I the application up on a server I believe this will save the file on the server harddrive.
Is it possible to send this file back to the client/browser some how?
public void CreateAnnuityExcelSheet(List<Calculation> cList, FormCollection form, int DTCyear)
{
List<Calculation> newList = new List<Calculation>();
newList.Add(cList.First()); //Getting the values for the first row
var StartValue = newList[0].StartValue;
var radio = form["advanceOrArrears"];
string fileName = newList[0].CalculationName;
string path = #"C:\ExcelFiles\" + fileName + ".xlsx"; //Path for the file
FileInfo info = new FileInfo(path);
info.Directory.Create(); //If C:\ExcelFiles does not exist, create it
if (!info.Exists)
{
using (ExcelPackage package = new ExcelPackage(info))
{
ExcelWorksheet ws = package.Workbook.Worksheets.Add(fileName);
//Styles for the sheet
package.Save();
}
}
}
The easiest way would be to send the bytes as File to browser. If your library for creating Excel files allows you to save to stream (like for example ClosedXML does) then you can do in your MVC action
var stream = new MemoryStream();
workbook.SaveAs(stream);
stream.Position = 0;
return File(stream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml", "file.xlsx");
If you can't save it to memory stream then save it to server's disc and then you can just pass file path and content type to return File().
I've used a httphandler for sending the byte file object to the browser.
This link should help, Generating a file, then launching a secure download
So save the file on the server then transmit it to the user in your controller:
return new FilePathResult(myFilePath,
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")

SharpZipLib with MemoryStream

I have been developing a web application with asp.net and I have smoe question about SharZipLib. I have a file called Template.odt (from Open Office) and this file is a compacted file (like docx) and we have some other files inside it (manifiest, xml, images etc). I need to open this file change a file called content.xml and styles.xml and save in another .odt file and give to my client. But I'm not sure if we can use temporary files, so I was thinking how to do this using MemoryStream.
Look what I got:
protected byte[ GetReport() {
Stream inputStream = File.OpenRead(Server.MapPath("~/Odt/Template.odt"));
var zipInputStream = new ZipInputStream(inputStream);
var outputStream = new MemoryStream();
var zipOutputStream = new ZipOutputStream(outputStream);
ZipEntry entry = zipInputStream.GetNextEntry();
while (entry != null) {
if (entry.Name == "content.xml")
// how change the content ?
else if (entry.Name == "styles.xml")
// how change the content ?
// how to add it or create folders in the output ?
zipOutputStream.Write( ??? );
entry = zipInputStream.GetNextEntry();
}
zipOutputStream.Flush();
return outputStream.ToArray();
}
I'm not sure if it's right but I think it's on the way.
I try to take ExtraData from ZipEntry instance but I got it null, is it normal ?
Can someone help me?
Thank you
An example of how you can update ZIP files in memory can be found here:
http://wiki.sharpdevelop.net/SharpZipLib_Updating.ashx#Updating_a_zip_file_in_memory_1
In your case, you probably have to load content.xml into a XmlDocument or XDocument to modify it - but that depends on what you are trying to change exactly.
As a sidemark: when using streams, make sure you are disposing of them. The easiest way is to wrap the operation in using statement:
using(var inputStream = File.OpenRead(Server.MapPath("~/Odt/Template.odt")))
{
// ...
}
More information on that: http://www.codeproject.com/Articles/6564/Understanding-the-using-statement-in-C

Categories