Downloading a file from Azure Storage to client using Angular2 with .NET Web Api 2 - download

I am trying to download a 1GB file from blob storage into the client. I used before Memory Stream and I get OutOfMemory exception.
now I am trying to open a read stream from the blob and send it directly to the client.
[HttpGet]
[ResponseType(typeof(HttpResponseMessage))]
public async Task<HttpResponseMessage> DownloadAsync(string file)
{
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
var stream = await blob.OpenReadAsync("container", file);
result.Content = new StreamContent(stream);
return result;
}
The file is downloaded correctly, but the problem is: The code download the complete stream in the client, then the client sees the downloaded file.
I wanted the client to see the file as being downloaded, so the user knows that he is downloading something. Not just blocking the request and wait till it finished.
I am using FileSaver in Angular2:
this.controller.download('data.zip').subscribe(
data => {
FileSaver.saveAs(data, 'data.zip');
});
Has anybody an idea how to fix it?
Thank you!

To fix it you'd need to use the following javascript code instead:
var fileUri = "http://localhost:56676/api/blobfile"; //replace with your web api endpoint
var link = document.createElement('a');
document.body.appendChild(link);
link.href = fileUri;
link.click();
And then in your backend, make it like so:
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
var stream = await blob.OpenReadAsync("container", file);
result.Content = new StreamContent(stream);
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = "data.zip"
};
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
return result;

I had the same problem.
The Solution I sorted out was -
First thing, the expected behaviour can occur only when client tries to download the file from blob and usually I prefer downloading the file from the client itself.
As in your case, try to get file blob uri and do some operations as below to open file in browser using Angular Router or simply window.location.href.
window.location.href = “https://*/filename.xlsx”
This worked for me.

Related

Client-Side error when uploading image on server ASP.NET Core

I am struggling with uploading an image from thew client-side to a folder on the server-side in .Net Core.I used Postman to check if the method on the server-side is working and it does without any problem,but when I try to upload an image from the client-side,I get an error on the server-side of type NullReferenceException:Object reference not set to an instance of an object.This is the Post method on the server-side:
[HttpPost]
public async Task Post(IFormFile file)
{
if (string.IsNullOrWhiteSpace(_environment.WebRootPath))
{
_environment.WebRootPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot");
}
var uploads = Path.Combine(_environment.WebRootPath, "uploads");
//var fileName = file.FileName.Split('\\').LastOrDefault().Split('/').LastOrDefault();
if (!Directory.Exists(uploads)) Directory.CreateDirectory(uploads);
if (file.Length > 0)
{
using (var fileStream = new FileStream(Path.Combine(uploads, file.FileName), FileMode.Create))
{
await file.CopyToAsync(fileStream);
}
}
}
Apparently the method is thrown where I check if the length of the file is bigger than 0.On the client-side I get error "500 internal server error" and I tried to check using the debugger where exactly the error is thrown but i can't find anything that could resemble an error of some sort.This is the API method for the client-side:
public async Task UploadPictureAsync(MediaFile image)
{
User user = new User();
string pictureUrl = "http://10.0.2.2:5000/api/UploadPicture";
HttpContent fileStreamContent = new StreamContent(image.GetStream());
// user.Picture=GetImageStreamAsBytes(image.GetStream());
fileStreamContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data") {FileName=Guid.NewGuid() + ".Png",Name="image"};
fileStreamContent.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
HttpClientHandler clientHandler = new HttpClientHandler();
clientHandler.ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => { return true; };
using (var client = new HttpClient(clientHandler))
{
using (var formData = new MultipartFormDataContent())
{
formData.Add(fileStreamContent);
var response = await client.PostAsync(pictureUrl, formData);
if(response.IsSuccessStatusCode)
{
var result = response.Content.ReadAsStringAsync().Result;
}
}
}
}
The image is declared in the Model as byte array:
public byte[] Picture { get; set; }
Does someone understand why my POST method has this behavior since the server-side works perfectly but fails when I try to upload an image from the client-side?What I find weird though is that when i read the error and I look at the Content-Type it is "text/plain" instead of "form-data" and I have tried to set it at the MutipartFormDataContent like this:
formData.Headers.ContentType.MediaType = "multipart/form-data";
I also tried to set the MediaTypeHeaderValue on the client like this:
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/octet-stream"));
I still get the wrong content type.
I have also tried a different approach with Stream instead of MediaFile but without any luck as it did not even hit the break point in debugger mode for the response.Any help would be appreciated! :)
I have managed to find the answer finalllyyyyy!!!The problem was on the client-side as I suspected and guess what,it was all about the correct name.It turns out that since on the server side I have IFormFile file I had to change the client side to take the parameter name "file" instead of image as well so that it could work.Thank you #Jason for the suggestions as I didn't understand the error from the first place and did some debugging on the server-side to help me figure it out.

Web API - Setting Response.Content with byte[] / MemoryStream Contents not working properly

My requirement is to use Web API to send across the network, a zip file (consisting a bunch of files in turn) which should not be written anywhere locally (not written anywhere on the server/client disk). For zipping, I am using DotNetZip - Ionic.Zip.dll
Code at Server:
public async Task<IHttpActionResult> GenerateZip(Dictionary<string, StringBuilder> fileList)
{
// fileList is actually a dictionary of “FileName”,”FileContent”
byte[] data;
using (ZipFile zip = new ZipFile())
{
foreach (var item in filelist.ToArray())
{
zip.AddEntry(item.Key, item.Value.ToString());
}
using (MemoryStream ms = new MemoryStream())
{
zip.Save(ms);
data = ms.ToArray();
}
}
var result = new HttpResponseMessage(HttpStatusCode.OK);
MemoryStream streams = new MemoryStream(data);
//, 0, data.Length-1, true, false);
streams.Position = 0;
//Encoding UTFEncode = new UTF8Encoding();
//string res = UTFEncode.GetString(data);
//result.Content = new StringContent(res, Encoding.UTF8, "application/zip");
<result.Content = new StreamContent(streams);
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/zip");
//result.Content.Headers.ContentLength = data.Length;
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
result.Content.Headers.ContentDisposition.FileName = "test.zip";
return this.Ok(result);
}
The issue I am facing is that after the zip file downloaded at client end when modified as a test.bin has its stream contents (byte[] data in this example’s contents) missing. (I am getting back a test.zip file. When I change the file locally from test.zip to test.bin, I am seeing that the File’s contents as shown below. It does not contain the Response.Content values. P.S. I have also tried the MIME type “application/octet-stream” as well. No luck!)
Test.zip aka test.bin’s contents:
{"version":{"major":1,"minor":1,"build":-1,"revision":-1,"majorRevision":-1,"minorRevision":-1},
"content":{"headers":[{"key":"Content-Type","value":["application/zip"]},
{"key":"Content-Disposition","value":["attachment; filename=test.zip"]}]},
"statusCode":200,"reasonPhrase":"OK","headers":[],"isSuccessStatusCode":true}
Can someone please help me on how we can set result.Content with a MemoryStream object (I have seen example of “FileStream” at other places on google to set “result.Content” but I want to use MemoryStream object only!). I am highlighting this because I think the problem lies with setting the MemoryStream object to the result.Content (in order to properly save the streams content into the result.Content object)
P.S. I have also gone thru Uploading/Downloading Byte Arrays with AngularJS and ASP.NET Web API (and a bunch of other links) but it did not help me much… :(
Any help is greatly appreciated. Thanks a lot in advance :)
I got my issue solved!!
All I did was to change the Response Type to HttpResponseMessage and use "return result" in the last line rather than Ok(result) { i.e. HttpResponseMessage Type rather than OKNegiotatedContentResult Type)

Read both key values and files from multipart from data post request in ASP.NET WebAPI

I have an endpoint that needs to accept a file upload and also some other information from the client request. With the following code I can upload the file successfully but can't seem to figure out how to read the other info.
I make a test request from Postman with the following form data:
image -- myimage.jpg -- of type File
email -- a#b.com -- of type Text
The backend code looks like this:
[HttpPost]
public async Task<HttpResponseMessage> SharePhoto()
{
try
{
var provider = new MultipartMemoryStreamProvider();
var data = await Request.Content.ReadAsMultipartAsync(provider);
// this is how I get the image which I am succesfully passing to EmailService
var item = (StreamContent)provider.Contents[0];
using (var stream = new MemoryStream())
{
await item.CopyToAsync(stream);
String emailAddress;
EmailService.SendSharedPhoto(emailAddress, stream);
return Request.CreateResponse();
}
}
catch
{
// do stuff
}
}
In this example I am able to access provider.Contents[1] but can't seem to be able to get the value from it into emailAddress. I'm thinking it may be possible to use the same trick as the await item.CopyToASync(stream) from the image upload, but I'm hoping I can get a simpler solution to that. Any ideas?
I just barely answered a very similar question to this yesterday. See my answer here complete with sample controller code.
The method I ended up using is:
If the form elements are strings (and it worked for me since the mobiel frontend took responsability for input data) you can do this:
var streamContent = (StreamContent)provider.Contents[1];
var memStream = new MemoryStream();
await streamContent.CopyToAsync(memStream);
var actualString = Encoding.UTF8.GetString(x.ToArray());
If however the field needs to represent a collection of items, like for example the email list: ["a#b.com", "x#c.com"], etc a JavaScriptSerializer can be user, like so:
var streamContent = (StreamContent)provider.Contents[1];
var emailAddresses = await str.ReadAsStringAsync();
var jsSerializer = new JavaScriptSerializer();
var deserializedData = jsSerializer.Deserialize<string[]>(emailAddresses);
Note that this is nowhere near safe, though it is few lines of code and happens to work.

image upload to server in windows phone8 app

I want to upload an image from the gallery or live pic (camera capture task) with some params; x = "some string", y = "some string", z = "some integer" and uploadimage = name of file tag in form.
Can anyone please help me?
Uploading image for WP8 was pain to setup. Many of the examples I follow was outdated and this took me days to research and finally got one to work. There are a few ways to upload:
1) Convert the image to a string and then you can send the image converted string via HTTP request. I've used this approach for Android, but haven't tried it for WP.
2) Upload the image via FTP and the text data via HTTP.
You have 3 choices to upload any File to server.
Convert file into Stream - recommend way
Convert file into ByteArray
Convert file into String
After that you can use HttpClient package make a POST request to server. Here is the code to demonstrate FileUpload by converting it into Stream.
Code:
public async void methodToUploadFile()
{
StorageFile file = await StorageFile.GetFileFromPathAsync("Assets/MyImage.png");
// var fileBytes = await GetBytesAsync(file);
HttpClient client = new HttpClient();
// give the server URI here
Uri requestUri = new Uri("Full Server URI", UriKind.Absolute);
MultipartFormDataContent formdata = new MultipartFormDataContent();
formdata.Add(new StringContent("some string"), "x");
formdata.Add(new StringContent("some string"), "y");
formdata.Add(new StringContent("some integer"), "z");
formdata.Add(new StreamContent(await file.OpenStreamForReadAsync()), "file", "MyImage.png");
// formdata.Add(new ByteArrayContent(fileBytes), "file", "MyImage.png");
// Make a POST request here
var res = await client.PostAsync(requestUri, formdata);
}
Hope this helps..!

How to upload file to Remote Server by windows phone

In web App, there is an Input Tag to upload file. In windows phone, It seems it is different. I need hlep on writing HttpWebRequest code to upload file to remote server ( if possible to skydrive). Can you show me how to solve this problem.
1) Upload file from Windows phone.
2) How would I handle the uploaded file on server-side If I use Asp.net.
Thanks.
Something like this. I suggest you ask about how to handle it on the server side in its own question with a different set of tags.
var uri = "http://example.com/some_applette"
var request = HttpWebRequest.create(uri);
request.Method = "POST";
request.ContentType = "image/jpeg"; // Change to whatever you're uploading.
request.BeginGetRequestStream((result1) =>
{
using (Stream stream = request.EndGetRequestStream(result1))
{
// Bytes contains the data to upload.
stream.Write(bytes, 0, bytes.Length);
}
request.BeginGetResponse((result2) =>
{
var response = request.EndGetResponse(result2);
// Optionally handle the response.
var responseStream = response.GetResponseStream();
...
}
}, null);

Resources