Downloading zip file from HttpRequestMessage : controller - asp.net

I'm working on a web api's using ASP.NET MVC's which download the zip file attached in the HttpRequestMessage
as below
var task = this.Request.Content.ReadAsStreamAsync();
task.Wait();
if (this.Request.Content.IsMimeMultipartContent())
{
using (Stream requestStream = task.Result)
{
// Do not know how to copy the above request to file stream or zip (ionic zip) and generate zip file from it
}
}
note:
1)
using (var fileStream = File.Create("name.zip"))
{
requestStream.CopyTo(fileStream);
}
creates invalid zip..
2) Zip contains many files inside it.
Waiting for your comments
Update 1:
var provider = new MultipartFormDataStreamProvider(ScriptPath);
Request.Content.ReadAsMultipartAsync(provider);
foreach (MultipartFileData file in provider.FileData)
{
Trace.Write(file.Headers.ContentDisposition.FileName);
Trace.Write("Server file path: " + ScriptPath);
}
though does not help me

This works for me. Please treat as pseudo as I didn't compile it. Also you may want to rework the blocking .Result call to take advantage of the Async read.
var requestStream = await Request.Content.ReadAsMultipartAsync();
HttpContent fileContent = requestStream.Contents.SingleOrDefault(c => c.Headers.ContentType != null);
byte[] fileBytes = await fileContent.ReadAsByteArrayAsync();
using (FileStream fs = File.OpenWrite(outputPath))
{
fs.Write(fileBytes, 0, (int)fileContent.Headers.ContentLength.Value);
}

Related

Aspose.Words Returning PDF as Stream does nothing (ASP.NET Web API)

We are exploring using Aspose.Words for some conversions in an on premise API.
This works perfectly for Excel sheets using Aspose.Cells.
[HttpPost]
[Route("convert/excel")]
public async Task<IActionResult> ConvertExcel(IFormFile fileToConvert)
{
var fileStream = new MemoryStream();
fileToConvert.CopyTo(fileStream);
var convertedFile = await pdfConverter.ConvertExcelAsync(fileStream);
return File(convertedFile, "application/octet-stream");
}
However when using exactly the same method for Aspose.Words it does nothing, literally nothing just continues for a few minutes and then times out. This is not a timeout issue with the conversion as the file is 200KB.
[HttpPost]
[Route("convert/word")]
public async Task<IActionResult> ConvertWord(IFormFile fileToConvert)
{
var fileStream = new MemoryStream();
fileToConvert.CopyTo(fileStream);
var convertedFile = await pdfConverter.ConvertWordAsync(fileStream);
return File(convertedFile, "application/octet-stream");
}
I have tried various forms of returning a file but no luck.
return new FileStreamResult(convertedFile, "application/pdf");
The actual conversion methods look like this.
public Task<Stream> ConvertWordAsync(Stream fileStream)
{
return Task.Factory.StartNew(() => ConvertWord(fileStream));
}
private Stream ConvertWord(Stream inputFile)
{
var doc = new Document(inputFile);
var outputFile = new MemoryStream();
doc.Save(outputFile, Aspose.Words.SaveFormat.Pdf);
//doc.Save(#"C:\ProgramData\foo.pdf", Aspose.Words.SaveFormat.Pdf); //THIS WORKS BUT NOT APPOPRIATE
return outputFile;
}
I have also updated it to support HttpGet and hard-coded a path to a file and in browser just get a Download failed - network error.
Is is possible that the Save method returns the memory stream at the end of the stream.
You should try the following immediately after the call to doc.Save
outputFile.Seek(0, SeekOrigin.Begin);

Zip Azure Storage Files and Return File from Web Api

I am trying to create a zip file with SharpZipLib from files stored on Azure Storage. Unfortunately I am not able to return them because the Api always returns a Json:
{"Version":{"Major":1,"Minor":1,"Build":-1,"Revision":-1,"MajorRevision":-1,"MinorRevision":-1},"Content":{"Headers":[{"Key":"Content-Disposition","Value":["attachment; filename=Documents.zip"]},{"Key":"Content-Type","Value":["application/octet-stream"]},{"Key":"Content-Length","Value":["498"]}]},"StatusCode":200,"ReasonPhrase":"OK","Headers":[],"RequestMessage":null,"IsSuccessStatusCode":true}
The zipping should work which I use, however I am not sure if everything is correct since I was never able to see the file.
This is the code for zipping the files and returning the zip file:
[HttpGet("DownloadFiles")]
public async Task<HttpResponseMessage> DownloadFiles(string invoiceNr, List<string> fileNames)
{
List<CloudBlockBlob> blobs = _documentService.GetBlobs(invoiceNr, fileNames);
MemoryStream outputMemStream = new MemoryStream();
ZipOutputStream zipStream = new ZipOutputStream(outputMemStream);
zipStream.SetLevel(3); //0-9, 9 being the highest level of compression
foreach (CloudBlockBlob blob in blobs)
{
using (MemoryStream blobStream = new MemoryStream())
{
await blob.DownloadToStreamAsync(blobStream);
ZipEntry newEntry = new ZipEntry(blob.Name);
newEntry.DateTime = DateTime.Now;
zipStream.PutNextEntry(newEntry);
StreamUtils.Copy(blobStream, zipStream, new byte[4096]);
zipStream.CloseEntry();
}
}
zipStream.IsStreamOwner = false; // False stops the Close also Closing the underlying stream.
zipStream.Close(); // Must finish the ZipOutputStream before using outputMemStream.
outputMemStream.Position = 0;
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
result.Content = new StreamContent(outputMemStream);
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
result.Content.Headers.ContentDisposition.FileName = "Documents.zip";
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
result.Content.Headers.ContentLength = outputMemStream.Length;
return result;
}
Is it the wrong way of returning a file from WebAPi? Am I doing something wrong in general?
Thanks in advance for the help.
As you declare your web method as
public async Task<HttpResponseMessage> DownloadFiles(...)
ASP.NET Core treats HttpResponseMessage as model and your methods returns instance of this file serialized as JSON.
The correct version of this method is
public async Task<IActionResult> DownloadFiles()
{
...
return File(outputMemStream, "application/octet-stream", "Documents.zip");
}

Wait till file is uploaded async to start next task

I need to process an XML file once it is uploaded. How do I check if the files are completely uploaded before I start the new method to do work on the file?
[HttpPost]
public async Task<IActionResult> UploadFile(ICollection<IFormFile> files)
{
var uploads = Path.Combine(_environment.WebRootPath, "uploads");
foreach (var file in files)
{
if (file.Length > 0)
{
fileName = Path.GetFileName(file.FileName);
using (var fileStream = new FileStream(Path.Combine(uploads, fileName), FileMode.Create))
{
await file.CopyToAsync(fileStream);
}
}
}
ProcessFile();
return View("NewProject");
}
private void ProcessFile()
{
//Do WORK
}
Right now it starts to Process the file while it's still being uploaded. How can I wait till upload is finished and check that the file is uploaded before Processing the File?
Have a look at this link FileStream Reading. As per your problem, you need to do a length check for the contents of the file and when all the content is read, do the await call.

How do I use response from an web api returning an image?

I have two web asp.net mvc based projects.
The first one has an image preview api, is implemented somewhat like this...
private async Task <HttpResponseMessage> GetImage(int id)
{
string filePath = "abstractedforsimplicity.png";
using(var file = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, true))
{
byte[] buff = new byte[file.Length];
await file.ReadAsync(buff, 0, (int) file.Length);
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new ByteArrayContent(buff)
};
result.Content.Headers.ContentType = new MediaTypeHeaderValue("image/png");
return result;
}
}
this works, I am able to show a preview with the following url - domain/api/image/3
Now I am a different application where I want to again make use of the same preview. I do not want to expose this api directly, so will be making a proxy api which will be making the call internally.
public HttpResponseMessage GetImage(int id)
{
string tempalteUrl = string.Format("{0}/{1}", ConfigurationManager.AppSettings["rmgpubadmin:template-base-url"], id);
WebClient client = new WebClient();
byte[] bytes = client.DownloadData(tempalteUrl);
// not very sure what should i do here ??
return null;
}
I tried to converting the bytes to an object, but if fails with errors - System.Runtime.Serialization.SerializationException.
The input stream is not a valid binary format. The starting contents (in bytes) are: 89-50-4E-47-0D-0A-1A-0A-00-00-00-0D-49-48-44-52-00 ...
What should i be doing here?

ASP.NET Core RC-1 file upload

I am currently uploading a file via the kendo fileuploader to an api controller using ASP.NET core RC-1. I am receiving a periodic error of "object reference not set to instance of object" when attempting to read the stream following opening the stream with IFormFile.OpenReadStream().
My controller is:
[HttpPost]
[Route("api/{domain}/[controller]")]
public async Task<IActionResult> Post([FromRoute]string domain, [FromForm]IFormFile file, [FromForm]WebDocument document)
{
if (ModelState.IsValid)
{
if (file.Length > 0)
{
var userName =
Request.HttpContext.User.Claims
.FirstOrDefault(c => c.Type == ClaimTypesEx.FullName)?
.Value;
var uploadedFileName =
ContentDispositionHeaderValue.Parse(file.ContentDisposition).FileName.Trim('"');
document.Domain = domain;
document.MimeType = file.ContentType;
document.SizeInBytes = file.Length;
document.ChangedBy = userName;
document.FileName = (string.IsNullOrEmpty(document.FileName)) ? uploadedFileName : document.FileName;
try
{
document = await CommandStack.For<WebDocument>()
.AddOrUpdateAsync(document, file.OpenReadStream()).ConfigureAwait(false);
}
catch (Exception e)
{
return new HttpStatusCodeResult(500);
}
return Ok(document);
}
}
return new BadRequestResult();
}
And the error is being thrown when I actually try to read the stream when it is going into blob storage:
public async Task<Uri> CreateOrUpdateBlobAsync(string containerName, string fileName, string mimeType,
Stream fileStream)
{
var container = Client.GetContainerReference(containerName);
var blob = container.GetBlockBlobReference(fileName);
//Error HERE
await blob.UploadFromStreamAsync(fileStream);
blob.Properties.ContentType = mimeType;
await blob.SetPropertiesAsync();
return blob.Uri;
}
What I am having trouble with is this is sporadic and there seems to be no defined pattern of which files are accepted and which ones generate the error. At first I thought it might be a size issue but that is not the case as I have several larger files uploaded successfully and then one small file will throw the error. Images seem to work fine and it is hit or miss on other file types with no rhyme or reason that I can figure out.

Resources