C# UWP HttpWebResponse Chunked - c#

I have problem with read stream Response because I can't read response to end.
This is respon from Server :
Server : "Apache-Coyote/1.1"
Transfer-Encoding : "chunked"
Content-Type: "multipart/mixed; boundary=F34D3847AEDEB14FF5967BF7426EECF6"
I try read this response :
var response = (HttpWebResponse)await httpWebRequest.GetResponseAsync();
using(var read = new StreamReader(response.GetResponseStream())
{
var result = await read.ReadToEndAsync();
}
and this method :
StringBuilder sb = new StringBuilder();
Byte[] buf = new byte[8192];
Stream resStream = response.GetResponseStream();
string tmpString = null;
int count = 0;
do
{
count = resStream.Read(buf, 0, buf.Length);
if(count != 0)
{
tmpString = Encoding.ASCII.GetString(buf, 0, count);
sb.Append(tmpString);
}
}while (count > 0);
Error Message :
Exception from HRESULT: 0x80072EE4
I/O error occurred.
Exception thrown: 'System.IO.IOException' in mscorlib.ni.dll
Exception thrown: 'System.IO.IOException' in mscorlib.ni.dll
Unfortunately it doesn't work, gets only fragments of response. Thank you for your help

I tested your code, for the first method you took, it works fine by me, I just added a Dispose() in it. And for the second method, I think it may be the problem that you didn't get the ContentLength of your var response.
Here is my code, and the commented part of the code is the first method, I took a Button Click event to handle this:
public async void HTTP(object sender, RoutedEventArgs e)
{
HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create("URL");
HttpWebResponse response = (HttpWebResponse)await httpWebRequest.GetResponseAsync();
Stream resStream = response.GetResponseStream();
StringBuilder sb = new StringBuilder();
StreamReader read = new StreamReader(resStream);
string tmpString = null;
int count = (int)response.ContentLength;
int offset = 0;
Byte[] buf = new byte[count];
do
{
int n = resStream.Read(buf, offset, count);
if (n == 0) break;
count -= n;
offset += n;
tmpString = Encoding.ASCII.GetString(buf, 0, buf.Length);
sb.Append(tmpString);
} while (count > 0);
text.Text = tmpString;
read.Dispose();
//using (StreamReader read = new StreamReader(resStream))
//{
// var result = await read.ReadToEndAsync();
// text.Text = result;
// read.Dispose();
//}
response.Dispose();
}
I've tested it, and it works fine.

Related

Download file using httprequest in C# Code

I am try to download pdf file from below code using webRequest in C# Code.I have tried below code but no error and no output is showing.Please check this below code and advise how to do this...
Note:
PlayResponeAsync method is not executing When I debug
I am using .Net framework 4.0
private static void DownloadCurrent() {
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create("https://einvoicing
.internal.cleartax.co/v2/eInvoice/download?
irns=11eaf48a909dda520db27ff35804d4b42df2c3b6285afee8df586cc4dbd10541");
webRequest.Method = "GET";
webRequest.ContentType = "application/pdf";
webRequest.Headers.Add("owner_id", "78c6beda-54a2-11ea-b064-0af3f8b02c24");
webRequest.Headers.Add("gstin", "29AAFCD5862R000");
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) { }
}

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;
}

Posting to Foursquare API fails

I have been working on a Foursquare app for WIndows Mobile 6 (as I still have at least 6months on my contract) I am failing on every attempt to POST data (ie Checkin) so it is not much use. Any suggestions or pointers on why this code always fails at the
oOutStream = request.GetRequestStream();
Line - HELP PLEASE.
public HTTPPost(Uri Url, Dictionary<string, string> Parameters)
{
StringBuilder respBody = new StringBuilder();
request = (HttpWebRequest)HttpWebRequest.Create(Url);
request.UserAgent = "4SqLite 20110803";
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.Timeout = 12000000;
string content = "?";
foreach (string k in Parameters.Keys)
{
content += k + "=" + Parameters[k] + "&";
}
content = content.TrimEnd(new char[] { '&' });
ASCIIEncoding encoding = new ASCIIEncoding();
byte[] byte1 = encoding.GetBytes(content);
request.ContentLength = byte1.Length;
byte[] buf = new byte[8192];
Stream oOutStream = null;
int tmp = ServicePointManager.DefaultConnectionLimit;
try
{
// send the Post
oOutStream = request.GetRequestStream();
}
catch
{
MessageBox.Show("Oops! We couldn't send data to the Internet. Try again later.", "HttpPost: Request error",
MessageBoxButtons.OK, MessageBoxIcon.Hand, MessageBoxDefaultButton.Button1);
}
finally
{
if (oOutStream != null)
{
oOutStream.Write(byte1, 0, byte1.Length); //Send it
oOutStream.Close();
}
}
try
{
// get the response
response = (HttpWebResponse)request.GetResponse();
Stream respStream = response.GetResponseStream();
int count = 0;
do
{
count = respStream.Read(buf, 0, buf.Length);
if (count != 0)
respBody.Append(Encoding.ASCII.GetString(buf, 0, count));
}
while (count > 0);
respStream.Close();
ResponseBody = respBody.ToString();
EscapedBody = GetEscapedBody();
}
catch
{
MessageBox.Show("Oops! We couldn't get data from the Internet. Try again later.", "HttpPost: Response error",
MessageBoxButtons.OK, MessageBoxIcon.Hand, MessageBoxDefaultButton.Button1);
}
finally
{
StatusCode = GetStatusLine();
Headers = GetHeaders();
response.Close();
}

Download the first 1000 bytes

I need to download a text file from the internet using C#. The file size can be quite large and the information I need is always within the first 1000 bytes. Is this possible?
Stolen from here.
string GetWebPageContent(string url)
{
string result = string.Empty;
HttpWebRequest request;
const int bytesToGet = 1000;
request = WebRequest.Create(url) as HttpWebRequest;
//get first 1000 bytes
request.AddRange(0, bytesToGet - 1);
// the following code is alternative, you may implement the function after your needs
using (WebResponse response = request.GetResponse())
{
using (Stream stream = response.GetResponseStream())
{
byte[] buffer = new byte[1024];
int read = stream.Read(buffer, 0, 1000);
Array.Resize(ref buffer, read);
return Encoding.ASCII.GetString(buffer);
}
}
}
(Edited as requested in the comments... ;) )
I did this as an answer to your newer question. You could put the range header in too if you want, but I excluded it.
string GetWebPageContent(string url)
{
//string result = string.Empty;
HttpWebRequest request;
const int bytesToGet = 1000;
request = WebRequest.Create(url) as HttpWebRequest;
var buffer = new char[bytesToGet];
using (WebResponse response = request.GetResponse())
{
using (StreamReader sr = new StreamReader(response.GetResponseStream()))
{
sr.Read(buffer, 0, bytesToGet);
}
}
return new string(buffer);
}

Categories