Trouble writing zip content to device. Writing as hexa data not xml - c#

I'm trying to download a zip file that contains an xml file and save the xml file to the device.
I'm able to save the file inside the zip but when I open the file it contains hexa data and not xml.
What I'm doing:
I'm using http client to make a get call. I get stream content from the response and using dependency injection, I pass the stream to a method that writes to the device.
In share code:
public static async Task<bool> Download()
{
var url = "some url";
HttpClientHandler handler = new HttpClientHandler()
{
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
};
var httpClient = new HttpClient(handler);
try
{
var response = await httpClient.GetAsync(url);
var total = response.Content.Headers.ContentLength.HasValue ? response.Content.Headers.ContentLength.Value : -1L;
var stream = await response.Content.ReadAsStreamAsync();
DependencyService.Get<IFileHelper>().WriteToFilePath("download", stream, total);
}
catch (Exception e)
{
//Handle exception
}
return true;
}
in iOS:
public async void WriteToFilePath(string filename, Stream responseStream, long contentSize)
{
var downloadFilePath = GetLocalFilePath(filename);
int receivedBytes = 0;
using (FileStream fileOut = File.Create(downloadFilePath))
{
using (Stream stream = responseStream)
{
byte[] buffer = new byte[4096];
for (;;)
{
int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
if (bytesRead == 0)
{
await Task.Yield();
break;
}
else
{
System.Diagnostics.Debug.WriteLine(bytesRead);
fileOut.Write(buffer, 0, bytesRead);
}
receivedBytes += bytesRead;
System.Diagnostics.Debug.WriteLine("receivedBytes: " + receivedBytes + " contentSize: " + contentSize);
}
}
}

Related

Bot Framework - Using Custom Speech Service Error 400 C#

I created a bot with bot framework and now i'm trying to use the CustomSpeech service instead of the bing SpeechToText Service that works fine. I have tried various way to resolve the problem but i get the error 400 and i don't know how to solve this.
The method where i would like to get the text from a Stream of a wav pcm audio:
public static async Task<string> CustomSpeechToTextStream(Stream audioStream)
{
audioStream.Seek(0, SeekOrigin.Begin);
var customSpeechUrl = "https://westus.stt.speech.microsoft.com/speech/recognition/interactive/cognitiveservices/v1?cid=<MyEndPointId>";
string token;
token = GetToken();
HttpWebRequest request = null;
request = (HttpWebRequest)HttpWebRequest.Create(customSpeechUrl);
request.SendChunked = true;
//request.Accept = #"application/json;text/xml";
request.Method = "POST";
request.ProtocolVersion = HttpVersion.Version11;
request.ContentType = "audio/wav; codec=\"audio/pcm\"; samplerate=16000";
request.Headers["Authorization"] = "Bearer " + token;
byte[] buffer = null;
int bytesRead = 0;
using (Stream requestStream = request.GetRequestStream())
{
// Read 1024 raw bytes from the input audio file.
buffer = new Byte[checked((uint)Math.Min(1024, (int)audioStream.Length))];
while ((bytesRead = audioStream.Read(buffer, 0, buffer.Length)) != 0)
{
requestStream.Write(buffer, 0, bytesRead);
}
requestStream.Flush();
}
string responseString = string.Empty;
// Get the response from the service.
using (WebResponse response = request.GetResponse()) // Here i get the error
{
using (StreamReader sr = new StreamReader(response.GetResponseStream()))
{
responseString = sr.ReadToEnd();
}
}
dynamic deserializedResponse = Newtonsoft.Json.JsonConvert.DeserializeObject(responseString);
if (deserializedResponse.RecognitionStatus == "Success")
{
return deserializedResponse.DisplayText;
}
else
{
return null;
}
}
At using (WebResponse response = request.GetResponse()){} i get an exception (Error 400).
Am I doing the HttpWebRequest in the right way?
I read in internet that maybe the problem is the file audio... but then why with the same Stream bing speech service doesn't return this error?
In my case the problem was that i had a wav stream audio that doesn't had the file header that Cris (Custom Speech Service) needs. The sulution is creating a temporary file wav, read the file wav and copy it in a Stream to send it as array to Cris
byte[] buffer = null;
int bytesRead = 0;
using (Stream requestStream = request.GetRequestStream())
{
buffer = new Byte[checked((uint)Math.Min(1024, (int)audioStream.Length))];
while ((bytesRead = audioStream.Read(buffer, 0, buffer.Length)) != 0)
{
requestStream.Write(buffer, 0, bytesRead);
}
requestStream.Flush();
}
or copy it in a MemoryStream and send it as array
using (Stream requestStream = request.GetRequestStream())
{
requestStream.Write(audioStream.ToArray(), 0, audioStream.ToArray().Length);
requestStream.Flush();
}

Web API service hangs on reading the stream

Description: I am modifying the ASP.NET Core Web API service (hosted in Windows Service) that supports resumable file uploads. This works fine and resumes file uploads in many failure conditions except one described below.
Problem: When the service is on ther other computer and the client is on mine and I unplug the cable on my computer, the client detects the absence of network while the service hangs on fileSection.FileStream.Read(). Sometimes the service detects the failure in 8 min, sometimes in 20, sometimes never.
I also noticed that after I unplug cable and stop the client, the service becomes stuck at Read() function and the file size is x KB, but when the service finally detects the exception some time later, it writes additional 4 KB to the file. This is weird because I turned off buffering and the buffer size is 2 KB.
Question: How to properly detect the absence of network on the service, or timeout properly, or cancel the request
The service code:
public static async Task<List<(Guid, string)>> StreamFileAsync(
this HttpRequest request, DeviceId deviceId, FileTransferInfo transferInfo)
{
var boundary = GetBoundary(MediaTypeHeaderValue.Parse(request.ContentType), DefaultFormOptions.MultipartBoundaryLengthLimit);
var reader = new MultipartReader(boundary, request.Body);
var section = await reader.ReadNextSectionAsync(_cancellationToken);
if (section != null)
{
var fileSection = section.AsFileSection();
var targetPath = transferInfo.FileTempPath;
try
{
using (var outfile = new FileStream(transferInfo.FileTempPath, FileMode.Append, FileAccess.Write, FileShare.None))
{
var buffer = new byte[DefaultCopyBufferSize];
int read;
while ((read = fileSection.FileStream.Read(buffer, 0, buffer.Length)) > 0) // HANGS HERE
{
outfile.Write(buffer, 0, read);
transferInfo.BytesSaved = read + transferInfo.BytesSaved;
}
}
}
catch (Exception e)
{
...
}
}
}
The client code:
var request = CreateRequest(fileTransferId, boundary, header, footer, filePath, offset, headers, null);
using (Stream formDataStream = request.GetRequestStream())
{
formDataStream.ReadTimeout = 60000;
formDataStream.Write(Encoding.UTF8.GetBytes(header), 0, header.Length);
byte[] buffer = new byte[2048];
using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
{
fs.Seek(offset, SeekOrigin.Begin);
for (int i = 0; i < fs.Length - offset;)
{
int k = await fs.ReadAsync(buffer, 0, buffer.Length);
if (k > 0)
{
await Task.Delay(100);
await formDataStream.WriteAsync(buffer, 0, k);
}
i = i + k;
}
}
formDataStream.Write(footer, 0, footer.Length);
}
var uploadingResult = request.GetResponse() as HttpWebResponse;
private static HttpWebRequest CreateRequest(
Guid fileTransferId,
string boundary,
string header,
byte[] footer,
string filePath,
long offset,
NameValueCollection headers,
Dictionary<string, string> postParameters)
{
var url = $"{_BaseAddress}v1/ResumableUpload?fileTransferId={fileTransferId}";
HttpWebRequest request = (HttpWebRequest) WebRequest.Create(url);
request.Method = "POST";
request.ContentType = "multipart/form-data; boundary=\"" + boundary + "\"";
request.UserAgent = "Agent 1.0";
request.Headers.Add(headers); // custom headers
request.Timeout = 120000;
request.KeepAlive = true;
request.AllowReadStreamBuffering = false;
request.ReadWriteTimeout = 120000;
request.AllowWriteStreamBuffering = false;
request.ContentLength = CalculateContentLength(filePath, offset, header, footer, postParameters, boundary);
return request;
}
What I tried:
I added these in into config files:
Tried to set timeout on the server
var host = new WebHostBuilder().UseKestrel(o => { o.Limits.KeepAliveTimeout = TimeSpan.FromMinutes(2);})
Used async and non-async Read()
Tried with keep alive and without
Tried to abort the request when network was restored: request?.Abort();
Tried to set formDataStream.ReadTimeout = 60000;
Since I did not find a better way, I decided to add a timeout to the reading stream and saving it to the file. The good example was posted here: https://blogs.msdn.microsoft.com/pfxteam/2012/10/05/how-do-i-cancel-non-cancelable-async-operations/
public static async Task<List<(Guid, string)>> StreamFileAsync(this HttpRequest request, DeviceId deviceId, FileTransferInfo transferInfo)
{
var boundary = GetBoundary(MediaTypeHeaderValue.Parse(request.ContentType), DefaultFormOptions.MultipartBoundaryLengthLimit);
var reader = new MultipartReader(boundary, request.Body);
var section = await reader.ReadNextSectionAsync(_cancellationToken);
if (section != null)
{
var fileSection = section.AsFileSection();
var targetPath = transferInfo.FileTempPath;
try
{
await SaveMyFile(...);
}
catch (OperationCanceledException){...}
catch (Exception){...}
}
}
private static async Task SaveMyFile(...)
{
var cts = CancellationTokenSource.CreateLinkedTokenSource(myOtherCancellationToken);
cts.CancelAfter(streamReadTimeoutInMs);
var myReadTask = StreamFile(transferInfo, fileSection, cts.Token);
await ExecuteMyTaskWithCancellation(myReadTask, cts.Token);
}
private static async Task<T> ExecuteMyTaskWithCancellation<T>(Task<T> task, CancellationToken cancellationToken)
{
var tcs = new TaskCompletionSource<bool>();
using (cancellationToken.Register(s => ((TaskCompletionSource<bool>) s).TrySetResult(true), tcs))
{
if (task != await Task.WhenAny(task, tcs.Task))
{
throw new OperationCanceledException(cancellationToken);
}
}
return await task;
}
private static async Task<bool> StreamFile(...)
{
using (var outfile = new FileStream(transferInfo.FileTempPath, FileMode.Append, FileAccess.Write, FileShare.None))
{
var buffer = new byte[DefaultCopyBufferSize];
int read;
while ((read = await fileSection.FileStream.ReadAsync(buffer, 0, buffer.Length, token)) > 0)
{
if (token.IsCancellationRequested)
{
break;
}
await outfile.WriteAsync(buffer, 0, read);
transferInfo.BytesSaved = read + transferInfo.BytesSaved;
}
return true;
}
}

how to return a xlsx file using memorystream web api

I am successfully making a web request, creating xlsx file and saving it to a directory. I would like to stream it and return it to the client without actually saving it on the server.
this is what i am currently using, it works fine
private string generateStudyTemplate(string requestId)
{
var serviceUrl = ConfigurationManager.AppSettings["serviceUrl"];
// create webRequest
HttpWebRequest webRequest = createWebRequest(serviceUrl + "/" + requestId);
// begin async call to web request
IAsyncResult asyncResult = webRequest.BeginGetResponse(null, null);
// suspend this thread until call is complete. You might want to
// do something usefull here like update your UI
asyncResult.AsyncWaitHandle.WaitOne();
// get the response from the completed web request
var filename = string.Format("{0}.xlsx", "NewWorkbook");
string physicalPath = HttpContext.Current.Server.MapPath("/FilesForExport");
string relativePath = Path.Combine(physicalPath, filename).Replace("\\", "/");
var filePath = relativePath;
// var filePath = directory + "\\NewWorkbook.xlsx";
using (WebResponse webResponse = webRequest.EndGetResponse(asyncResult))
{
var str = webResponse.GetResponseStream();
var inBuf = new byte[webResponse.ContentLength];
var bytesToRead = Convert.ToInt32(inBuf.Length);
var bytesRead = 0;
while (bytesToRead > 0)
{
var n = str.Read(inBuf, bytesRead, bytesToRead);
if (n == 0)
break;
bytesRead += n;
bytesToRead -= n;
}
var fstr = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.Write);
fstr.Write(inBuf, 0, bytesRead);
fstr.Close();
}
return filePath;
}
private static HttpWebRequest createWebRequest(string url)
{
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url);
webRequest.ContentType = "text/xml;charset=\"utf-8\"";
webRequest.Accept = "text/xml";
webRequest.Method = "GET";
return webRequest;
}
Here is what I have put together from some other examples.
public HttpResponseMessage GenerateMarketStudyResult([FromBody]Result id)
{
if (id.requestId == null)
{
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.BadRequest));
}
var serviceUrl = ConfigurationManager.AppSettings["serviceUrl"];
var streamContent = new PushStreamContent((outputStream, httpContext, transportContent) =>
{
try
{
HttpWebRequest webRequest = createWebRequest(serviceUrl + "/" + id.requestId);
IAsyncResult asyncResult = webRequest.BeginGetResponse(null, null);
asyncResult.AsyncWaitHandle.WaitOne();
using (WebResponse webResponse = webRequest.EndGetResponse(asyncResult))
{
using (MemoryStream memoryStream = new MemoryStream())
{
var str = webResponse.GetResponseStream();
var inBuf = new byte[webResponse.ContentLength];
var bytesToRead = Convert.ToInt32(inBuf.Length);
var bytesRead = 0;
while (bytesToRead > 0)
{
var n = str.Read(inBuf, bytesRead, bytesToRead);
if (n == 0)
break;
bytesRead += n;
bytesToRead -= n;
}
memoryStream.Write(inBuf, 0, bytesRead);
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
outputStream.Close();
}
});
streamContent.Headers.ContentType = new MediaTypeHeaderValue("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
streamContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
streamContent.Headers.ContentDisposition.FileName = "reports.xlsx";
var result = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = streamContent
};
return result;
}
I am not getting any exceptions, but the xlsx file is returning with 0bytes.
The breakpoint here
memoryStream.Write(inBuf, 0, bytesRead);
here is the javascript serving the returned file
$http.post('/api/GenerateMarketStudyResult/', Result, { responseType: 'arraybuffer' })
.success(function (response, status, headers, config) {
saveAs(new Blob([response], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }), 'reports.xlsx');
})
shows that the
bytesRead = 112336
I assume that you write a web service which acts as a proxy between your JavaScript and some third party web service.
First of all, if you use at least .NET 4.0, you can use the Stream.CopyTo method to copy a stream to another.
So instead of this:
using (WebResponse webResponse = webRequest.EndGetResponse(asyncResult))
{
var str = webResponse.GetResponseStream();
var inBuf = new byte[webResponse.ContentLength];
var bytesToRead = Convert.ToInt32(inBuf.Length);
var bytesRead = 0;
while (bytesToRead > 0)
{
var n = str.Read(inBuf, bytesRead, bytesToRead);
if (n == 0) break;
bytesRead += n;
bytesToRead -= n;
}
var fstr = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.Write);
fstr.Write(inBuf, 0, bytesRead);
fstr.Close();
}
You could write:
using (var webResponse = webRequest.EndGetResponse(asyncResult))
using (var fstr = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.Write))
{
webResponse.GetResponseStream().CopyTo(fstr);
}
Second, assuming you use WCF to build a web service, you could pipe the response to a memory stream, and return it. (dont forget to reset the stream's position after you finished writing)
Put together:
[WebGet(UriTemplate = "GenerateMarketStudyResult/{id}")]
public Stream GenerateMarketStudyResult(string id)
{
var serviceUrl = ConfigurationManager.AppSettings["serviceUrl"];
// create webRequest
HttpWebRequest webRequest = createWebRequest(serviceUrl + "/" + id);
// begin async call to web request
IAsyncResult asyncResult = webRequest.BeginGetResponse(null, null);
// suspend this thread until call is complete. You might want to
// do something usefull here like update your UI
asyncResult.AsyncWaitHandle.WaitOne();
var memStream = new MemoryStream();
// var filePath = directory + "\\NewWorkbook.xlsx";
using (WebResponse webResponse = webRequest.EndGetResponse(asyncResult))
{
webResponse.GetResponseStream().CopyTo(memStream);
}
memStream.Position = 0;
var response = WebOperationContext.Current.OutgoingResponse;
response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
response.ContentLength = (int)memStream.Length;
return memStream;
}
EDIT:
You didn't copy the contents of the memoryStream to the outputStream. You can omit the memoryStream. Try this:
public HttpResponseMessage GenerateMarketStudyResult([FromBody]Result id)
{
if (id.requestId == null)
{
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.BadRequest));
}
var serviceUrl = ConfigurationManager.AppSettings["serviceUrl"];
var streamContent = new PushStreamContent((outputStream, httpContext, transportContent) =>
{
try
{
HttpWebRequest webRequest = createWebRequest(serviceUrl + "/" + id.requestId);
IAsyncResult asyncResult = webRequest.BeginGetResponse(null, null);
asyncResult.AsyncWaitHandle.WaitOne();
using (WebResponse webResponse = webRequest.EndGetResponse(asyncResult))
{
webResponse.GetResponseStream().CopyTo(outputStream);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
outputStream.Close();
}
});
streamContent.Headers.ContentType = new MediaTypeHeaderValue("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
streamContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
streamContent.Headers.ContentDisposition.FileName = "reports.xlsx";
var result = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = streamContent
};
return result;
}

Downloading files not affecting UI

We are currently downloading files using HttpClient because our backend requires certificate.
I have a control - FileRowwhich is an UI element with some code-behind methods for file downloading, like this one:
if (FileIsDownloaded == false)
{
await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Low, () =>
{
DataManager.Instance.DownloadFile(this);
});
}
if (ThumbnailIsDownloaded == false)
{
await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Low, () =>
{
DataManager.Instance.DownloadThumbnail(this);
});
}
Downloading single item is fine but when i click download all ( about 50 items ) the whole UI starts to freeze.
As you can see, i have tried to give requests low priority - but still same result.
Answers to common questions:
1) Yes the files should be downloadable all at one time, not one after another.
2) DataManager.Instance.DownloadThumbnail(this) - i do this to give refference to current control so that i could report a progress in a progress bar.
Any suggestions?
EDIT:
Downloading looks like this:
public async void DownloadFile(FileRow fileRow)
{
//Lot of checking for if file exist, if version is the same
string LocalFilename = await DownloadManager.DownloadFile(fileRow.MyFile.file.id, fileRow.MyFile.file.version, fileRow.MyFile.file.filename,fileRow);
// next is just using the filename string
}
And finally my download:
public static async Task<string> DownloadFileOfCustomerAssetRow(int? id, int? version, string filename, FileRow fileRow)
{
try
{
HttpClientHandler aHandler = new HttpClientHandler();
aHandler.ClientCertificateOptions = ClientCertificateOption.Automatic;
HttpClient aClient = new HttpClient(aHandler);
customerAssetRow.CurrentFileDownload = aClient;
aClient.DefaultRequestHeaders.ExpectContinue = false;
HttpResponseMessage response = await aClient.GetAsync(WebServices.BackendStartUrl + "getFileData?id=" + id + "&version=" + version, HttpCompletionOption.ResponseHeadersRead);
var file = await ApplicationData.Current.LocalFolder.CreateFileAsync(filename, Windows.Storage.CreationCollisionOption.GenerateUniqueName);
fileRow.FileName = file.Name;
using (var fs = await file.OpenAsync(Windows.Storage.FileAccessMode.ReadWrite))
{
Stream stream = await response.Content.ReadAsStreamAsync();
IInputStream inputStream = stream.AsInputStream();
ulong totalBytesRead = 0;
while (true)
{
IBuffer buffer = new Windows.Storage.Streams.Buffer(1024);
buffer = await inputStream.ReadAsync(
buffer,
buffer.Capacity,
InputStreamOptions.None);
if (buffer.Length == 0)
{
break;
}
totalBytesRead += buffer.Length;
fileRow.Progress.Value = fileRow.Progress.Value + 1024;
await fs.WriteAsync(buffer);
}
inputStream.Dispose();
}
fileRow.Progress.Visibility = Visibility.Collapsed;
return file.Name;
}
catch (Exception e)
{
ErrorReporter.ReportError("Error in DownloadManager.cs in function DownloadFile.", e);
return "";
}
}
It's possible that your async method continuations are interrupting the UI thread too much. Try creating a stronger separation between your background logic (DownloadFileOfCustomerAssetRow) and your UI (FileRow) by introducing an IProgress<T> reporter. Then ensure that every await in your background logic has a ConfigureAwait(false) on it.
public static async Task<string> DownloadFileOfCustomerAssetRow(int? id, int? version, string filename, IProgress<int> progress)
{
HttpClientHandler aHandler = new HttpClientHandler();
aHandler.ClientCertificateOptions = ClientCertificateOption.Automatic;
HttpClient aClient = new HttpClient(aHandler);
customerAssetRow.CurrentFileDownload = aClient;
aClient.DefaultRequestHeaders.ExpectContinue = false;
HttpResponseMessage response = await aClient.GetAsync(WebServices.BackendStartUrl + "getFileData?id=" + id + "&version=" + version, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false);
var file = await ApplicationData.Current.LocalFolder.CreateFileAsync(filename, Windows.Storage.CreationCollisionOption.GenerateUniqueName).ConfigureAwait(false);
fileRow.FileName = file.Name;
using (var fs = await file.OpenAsync(Windows.Storage.FileAccessMode.ReadWrite).ConfigureAwait(false))
{
Stream stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
IInputStream inputStream = stream.AsInputStream();
ulong totalBytesRead = 0;
while (true)
{
IBuffer buffer = new Windows.Storage.Streams.Buffer(1024);
buffer = await inputStream.ReadAsync(
buffer,
buffer.Capacity,
InputStreamOptions.None).ConfigureAwait(false);
if (buffer.Length == 0)
{
break;
}
totalBytesRead += buffer.Length;
if (progress != null)
progress.Report(totalBytesRead);
await fs.WriteAsync(buffer).ConfigureAwait(false);
}
inputStream.Dispose();
}
return file.Name;
}

How To Use HttpWebRequest/Response To Download A Binary (.exe) File From A Web Server?

I am writing a program that needs to download an .exe file from a website and then save it to the hard drive. The .exe is stored on my site and it's url is as follows (it's not the real uri just one I made up for the purpose of this question):
http://www.mysite.com/calc.exe
After many web searches and fumbling through examples here is the code I have come up with so far:
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(http://www.mysite.com/calc.exe);
HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse();
Stream responseStream = webResponse.GetResponseStream();
StreamReader streamReader = new StreamReader(responseStream);
string s = streamReader.ReadToEnd();
As you can see I am using the StreamReader class to read the data. After calling ReadToEnd does the stream reader contain the (binary) content of my .exe? Can I just write the content of the StreamReader to a file (named calc.exe) and I will have succesfully downloaded the .exe?
I am wondering why StreamReader ReadToEnd returns a string. In my case would this string be the binary content of calc.exe?
WebClient is the best method to download file. But you can use the following method to download a file asynchronously from web server.
private static void DownloadCurrent()
{
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create("[url to download]");
webRequest.Method = "GET";
webRequest.Timeout = 3000;
webRequest.BeginGetResponse(new AsyncCallback(PlayResponeAsync), webRequest);
}
private static void PlayResponeAsync(IAsyncResult asyncResult)
{
long total = 0;
long received = 0;
HttpWebRequest webRequest = (HttpWebRequest)asyncResult.AsyncState;
try
{
using (HttpWebResponse webResponse = (HttpWebResponse)webRequest.EndGetResponse(asyncResult))
{
byte[] buffer = new byte[1024];
FileStream fileStream = File.OpenWrite("[file name to write]");
using (Stream input = webResponse.GetResponseStream())
{
total = input.Length;
int size = input.Read(buffer, 0, buffer.Length);
while (size > 0)
{
fileStream.Write(buffer, 0, size);
received += size;
size = input.Read(buffer, 0, buffer.Length);
}
}
fileStream.Flush();
fileStream.Close();
}
}
catch (Exception ex)
{
}
}
There is a similar thread here - how to download the file using httpwebrequest
StreamReader is a text reader implementation i.e. it should be used to read text data and not binary data. In your case, you should be directly using the underlying response stream.
For downloading file, the simplest way would be to use WebClient.DownloadFile method.
This should directly save the file on your hard disk.
using System.Net;
using (WebClient webClient = new WebClient ())
{
webClient.DownloadFile("http://www.mysite.com/calc.exe", "calc.exe");
}
Instead of using StreamReader, you should really call Read() method of your Stream object. That will ask you for a byte[] buffer to be fill with read data, which you can then write to disk using StreamWriter or FileStream.
I'm probably a little bit late but I had the same problem with files being always 0kb big if not running in Debug mode.. This might be a relatively simple answer but disabling "DEBUG-Constants" under Properties solved it for me.
I have created a class with events so you can track download progress:
using System;
using System.IO;
using System.Net;
using System.Net.Mime;
//event examples: https://www.tutorialsteacher.com/csharp/csharp-event
public class HttpWebRequestDownload
{
private long _totalBytesLength = 0;
private long _transferredBytes = 0;
private int _transferredPercents => (int)((100 * _transferredBytes) / _totalBytesLength);
private string _defaultDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
public string downloadedFilePath = String.Empty;
public HttpWebRequestDownload(){
//Windows 7 fix
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
}
public void DownloadFile(string url, string destinationDirectory = default)
{
string filename = "";
if (destinationDirectory == default)
destinationDirectory = _defaultDirectory;
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Headers.Add("Cache-Control", "no-cache");
request.Headers.Add("Cache-Control", "no-store");
request.Headers.Add("Cache-Control", "max-age=1");
request.Headers.Add("Cache-Control", "s-maxage=1");
request.Headers.Add("Pragma", "no-cache");
request.Headers.Add("Expires", "-1");
if (!Directory.Exists(destinationDirectory))
{
Directory.CreateDirectory(destinationDirectory);
}
using (HttpWebResponse response = (HttpWebResponse)request.GetResponseAsync().Result)
{
_totalBytesLength = response.ContentLength;
string path = response.Headers["Content-Disposition"];
if (string.IsNullOrWhiteSpace(path))
{
var uri = new Uri(url);
filename = Path.GetFileName(uri.LocalPath);
}
else
{
ContentDisposition contentDisposition = new ContentDisposition(path);
filename = contentDisposition.FileName;
}
using (Stream responseStream = response.GetResponseStream())
using (FileStream fileStream = File.Create(System.IO.Path.Combine(destinationDirectory, filename)))
{
byte[] buffer = new byte[1024*1024]; // 1MB buffer
ProgressEventArgs eventArgs = new ProgressEventArgs(_totalBytesLength);
int size = responseStream.Read(buffer, 0, buffer.Length);
while (size > 0)
{
fileStream.Write(buffer, 0, size);
_transferredBytes += size;
size = responseStream.Read(buffer, 0, buffer.Length);
eventArgs.UpdateData(_transferredBytes, _transferredPercents);
OnDownloadProgressChanged(eventArgs);
}
}
}
downloadedFilePath = Path.Combine(destinationDirectory, filename);
OnDownloadFileCompleted(EventArgs.Empty);
}
catch (Exception e)
{
OnError($"{e.Message} => {e?.InnerException?.Message}");
}
}
//events
public event EventHandler<ProgressEventArgs> DownloadProgressChanged;
public event EventHandler DownloadFileCompleted;
public event EventHandler<string> Error;
public class ProgressEventArgs : EventArgs
{
public long TransferredBytes { get; set; }
public int TransferredPercents { get; set; }
public long TotalBytesLength { get; set; }
public ProgressEventArgs(long transferredBytes, int transferredPercents, long totalBytesLength)
{
TransferredBytes = transferredBytes;
TransferredPercents = transferredPercents;
TotalBytesLength = totalBytesLength;
}
public ProgressEventArgs(long totalBytesLength)
{
this.TotalBytesLength = totalBytesLength;
}
public void UpdateData(long transferredBytes, int transferredPercents)
{
TransferredBytes = transferredBytes;
TransferredPercents = transferredPercents;
}
}
protected virtual void OnDownloadProgressChanged(ProgressEventArgs e)
{
DownloadProgressChanged?.Invoke(this, e);
}
protected virtual void OnDownloadFileCompleted(EventArgs e)
{
DownloadFileCompleted?.Invoke(this, e);
}
protected virtual void OnError(string errorMessage)
{
Error?.Invoke(this, errorMessage);
}
}
Here is testing example:
static void Main(string[] args)
{
HttpWebRequestDownload hDownload = new HttpWebRequestDownload();
string downloadUrl = "http://speedtest.tele2.net/10MB.zip";
hDownload.DownloadProgressChanged += HDownloadOnDownloadProgressChanged;
hDownload.DownloadFileCompleted += delegate(object o, EventArgs args)
{
Debug.WriteLine("Download finished and saved to: "+hDownload.downloadedFilePath);
};
hDownload.Error += delegate(object o, string errMessage) { Debug.WriteLine("Error has occured !! => "+errMessage); };
hDownload.DownloadFile(downloadUrl);
}
private void HDownloadOnDownloadProgressChanged(object sender, HttpWebRequestDownload.ProgressEventArgs e)
{
Debug.WriteLine("progress: "+e.TransferredBytes+" => "+e.TransferredPercents);
}

Categories