I have a REST API endpoint which receives zip file on .Net Core 1.1. I'm getting IFormFile from request like this
var zipFile = HttpContext.Request.Form.Files.FirstOrDefault();
And then I need to pass it to service method from .Net Standard 1.5, where IFormFile is not supported.
So the question is: how can I convert IFormFile to ZipFile or to some other type which is supported in Standard 1.5, or maybe there is some more proper way to operate with zip files?
Thanks!
IFormFile is just a wrapper for the received file. You should still read the actual file do something about it. For example, you could read the file stream into a byte array and pass that to the service:
byte[] fileData;
using (var stream = new MemoryStream((int)file.Length))
{
file.CopyTo(stream);
fileData = stream.ToArray();
}
Or you could copy the stream into a physical file in the file system instead.
But it basically depends on what you actually want to do with the uploaded file, so you should start from that direction and the convert the IFormFile into the thing you need.
If you want to open the file as a ZIP and extract something from it, you could try the ZipArchive constructor that takes a stream. Something like this:
using (var stream = file.OpenReadStream())
using (var archive = new ZipArchive(stream))
{
var innerFile = archive.GetEntry("foo.txt");
// do something with the inner file
}
Related
https://forge.autodesk.com/en/docs/bim360/v1/tutorials/documen-management/upload-document/
I am following the tutorial above to upload a file into a BIM 360 folder through Autodesk Forge. I have reached Step 6: Upload the File to the Storage Object and I am trying to use the method UploadObjectAsync() to upload a file but I am getting an error stating: error getting value from 'ReadTimeout' on 'System.Web.HttpInputStream' and I am unsure how to fix this.
Am I using the wrong method or there something I am missing in the code? Below is the method I am using on .NET.
HttpPostedFile file = req.Files[0];
ObjectsApi objectsApi = new ObjectsApi();
dynamic objects = await objectsApi.UploadObjectAsync(bucketKey, objectName, file.ContentLength, file.InputStream);
Try use the underlying stream of a StreamReader from the file to upload, instead of the raw InputStream from multipart form:
using (StreamReader streamReader = new StreamReader(fileSavePath))
{
await objects.UploadObjectAsync(bucketKey, objectName,(int)streamReader.BaseStream.Length, streamReader.BaseStream, "application/octet-stream");
...
}
Given how the UploadObjectAsync and its chained method UploadObjectAsyncWith(code here) is implemented you'd better saved the posted file and then upload it instead of piping streams. See an example here.
I'm having trouble using the System.IO.Compression library to create a zip file and then return the byte[] for that zip file. So I want the method to take an input string--the path for the file to be zipped--and return the corresponding byte array for the file once it's been zipped. Currently, I can save the zip file to some known path and then use System.IO.File.ReadAllBytes(path) to get the byte[].
But how can I do this if I don't know beforehand where that zip file should end up (if anywhere at all)? My attempt at the solution is below. It doesn't seem to be working because when I try to reconstruct the zip file from the byte array it says that the archive is in an unknown format or damaged. Note: I've been able to do this using the Ionic DotNetZip library; however, I'm trying to do the same with only the use of System.IO libraries.
Any ideas on how to go about this?
private static byte[] CreateZipAndFindBytes(string importfile)
{
byte[] retVal = null;
using (System.IO.MemoryStream memStream = new System.IO.MemoryStream())
{
//ZipArchive(Stream, ZipArchiveMode, Boolean) //true means leave stream open
using (System.IO.Compression.ZipArchive archive = new System.IO.Compression.ZipArchive(memStream, System.IO.Compression.ZipArchiveMode.Create, true))
{
archive.CreateEntryFromFile(importfile, "test.zip"); //adds the file to the zip
}
retVal = memStream.ToArray();
}
return retVal;
}
entryName, the second parameter of CreateEntryFromFile is supposed to be "The name of the entry to create in the zip archive." It's not the name of your zip file.
you're zipping the import file, but also renaming it with a .zip extension, and I'm assuming that the import file is not actually a zip.
do this instead
archive.CreateEntryFromFile(importfile, importfile); //adds the file to the zip
I've looked around for a solution to my issue but no-one seems to being aiming for quite what I'm trying to achieve.
My problem is such, I have Zip files stored in Azure Blob storage, now for security's sake we have an API2 controller action that provisions these zip files, rather than allowing direct downloading. This action will retrieve the blob, and download it to a stream, so that it can be packaged within a HTTPResponseMessage.
All of the above works, however, when I attempt to recreate the zip file, I'm informed it's corrupted. For now I'm just attempting to have the server (running on localhost) create the zip file, whereas the endgame is to have remote Client applications do this (I'm fairly certain the solution to my issue on the server would be the same.
public class FileActionResult : IHttpActionResult
{
private HttpRequestMessage _request;
private ICloudBlob _blob;
public FileActionResult(HttpRequestMessage request, ICloudBlob blob)
{
_request = request;
_blob = blob;
}
public async Task<HttpResponseMessage> ExecuteAsync(System.Threading.CancellationToken cancellationToken)
{
var fileStream = new MemoryStream();
await _blob.DownloadToStreamAsync(fileStream);
var byteTest = new byte[fileStream.Length];
var test = fileStream.Read(byteTest, 0, (int)fileStream.Length);
try
{
File.WriteAllBytes(#"C:\testPlatFiles\test.zip", byteTest);
}
catch(ArgumentException ex)
{
var a = ex;
}
var response = _request.CreateResponse(HttpStatusCode.Accepted);
response.Content = new StreamContent(fileStream);
response.Content.Headers.ContentLength = _blob.Properties.Length;
response.Content.Headers.ContentType = new MediaTypeHeaderValue(_blob.Properties.ContentType);
//set the fileName
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = _blob.Name,
Size = _blob.Properties.Length
};
return response;
}
}
I've looked into Zip libraries to see if any present the solution for converting the stream of a zip back to a zip file, but all I can find is reading zip files into streams, or the creation in order to provision a file download instead of a filecreate.
Any help would be much appreciated, thank you.
You use DotNetZip. Its ZipFile class has a static factory method that should do what you want: ZipFile.Read( Stream zipStream ) reads the given stream as a zip file and gives you back a ZipFile instance (which you can use for whatever.
However, if your Stream contains the raw zip data and all you want to do is persist it to disk, you should just be able to write the bytes straight to disk.
If you're getting 'zip file corrupted' errors, I'd look at the content encoding used to send the data to Azure and the content encoding it's sent back with. You should be sending it up to Azure with a content type of application/zip or application/octet-stream and possibly adding metadata to the Azure blob entry to send it down the same way.
Edited To Note: DotNetZip used to live at Codeplex. Codeplex has been shut down. The old archive is still available at Codeplex. It looks like the code has migrated to Github:
https://github.com/DinoChiesa/DotNetZip. Looks to be the original author's repo.
https://github.com/haf/DotNetZip.Semverd. This looks to be the currently maintained version. It's also packaged up an available via Nuget at https://www.nuget.org/packages/DotNetZip/
I've basically copied this code sample directly from msdn with some minimal changes. The CopyTo method is silently failing and I have no idea why. What would cause this behavior? It is being passed a 78 KB zipped folder with a single text file inside of it. The returned FileInfo object points to a 0 KB file. No exceptions are thrown.
public static FileInfo DecompressFile(FileInfo fi)
{
// Get the stream of the source file.
using (FileStream inFile = fi.OpenRead())
{
// Get original file extension,
// for example "doc" from report.doc.cmp.
string curFile = fi.FullName;
string origName = curFile.Remove(curFile.Length
- fi.Extension.Length);
//Create the decompressed file.
using (FileStream outFile = File.Create(origName))
{
// work around for incompatible compression formats found
// here http://george.chiramattel.com/blog/2007/09/deflatestream-block-length-does-not-match.html
inFile.ReadByte();
inFile.ReadByte();
using (DeflateStream Decompress = new DeflateStream(inFile,
CompressionMode.Decompress))
{
// Copy the decompression stream
// into the output file.
Decompress.CopyTo(outFile);
return new FileInfo(origName);
}
}
}
}
In a comment you say that you are trying to decompress a zip file. The DeflateStream class can not be used like this on a zip file. The MSDN example you mentioned uses DeflateStream to create individual compressed files and then uncompresses them.
Although zip files might use the same algorithm (not sure about that) they are not just compressed versions of a single file. A zip file is a container that can hold many files and/or folders.
If you can use .NET Framework 4.5 I would suggest to use the new ZipFile or ZipArchive class. If you must use an earlier framework version there are free libraries you can use (like DotNetZip or SharpZipLib).
I'm needing to create a zipped document containing files that exist on the server. I am using the Ionic.Zip to do so, and to create a new Package (which is the zip file) I have to have either a path to a physical file or a stream. I am trying to not create an actual file that would be the zip file, instead just create a stream that would exist in memory or something. how can i do this?
Create the package using a MemoryStream then.
You can try the save method in the ZipFile Class. It can save to a stream
try this.
using (MemoryStream ms = new MemoryStream())
{
using (Ionic.Zip.ZipFile zipFile = new Ionic.Zip.ZipFile())
{
zipFile.AddFiles(filesToBeZipped, false, "NewFolder");//filesTobeZipped is a List<string>
zipFile.Save(ms);
}
}
You'll want to use the .AddEntry method on the ZipFile you've created specifying a name and the byte[] containing the actual file data.
ex.
ZipFile zipFile = new ZipFile();
zipFile.AddEntry(file.FileName, file.FileData);
where file.FileName will be the entry name (in the zip file) and file.FileData is the byte array.