Exceptions after AsyncCallback - c#

I'm having problems with an AsyncCallback function. I'm using one to download data, and then whatever I do after that, it throws a different exception. Some code:
private void downloadBtn_Click(object sender, RoutedEventArgs e)
{
string fileName = System.IO.Path.GetFileName(Globals.CURRENT_PODCAST.Title.Replace(" ", string.Empty));
MessageBox.Show("Download is starting");
file = IsolatedStorageFile.GetUserStoreForApplication();
streamToWriteTo = new IsolatedStorageFileStream(fileName, FileMode.Create, file);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(new Uri(Globals.CURRENT_PODCAST.Uri));
request.AllowReadStreamBuffering = false;
request.BeginGetResponse(new AsyncCallback(GetData), request);
}
private void GetData(IAsyncResult result)
{
HttpWebRequest request = (HttpWebRequest)result.AsyncState;
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(result);
Stream str = response.GetResponseStream();
byte[] data = new byte[16* 1024];
long totalValue = response.ContentLength;
while (str.Read(data, 0, data.Length) > 0)
{
if (streamToWriteTo.CanWrite)
streamToWriteTo.Write(data, 0, data.Length);
else
MessageBox.Show("Could not write to stream");
}
streamToWriteTo.Close();
MessageBox.Show("Download Finished");
}
Is there any way to tell when an async callback has finished, and then run code without crashing, or something I am doing wrong here?

The problem is that you're calling MessageBox.Show from a threadpool thread. You need to call it from the UI thread. To do that, you need to synchronize with the UI thread. For example:
this.Invoke((MethodInvoker) delegate
{ MessageBox.Show("success!"); });
The call to Invoke will execute the code on the UI thread. See documentation for Control.Invoke for more information.

Related

How wait asynchronous method in a thread?

I need that Join method is called when Download.file method have finished.
I tried to add await keyword but it didn't work
Thread myThread = new Thread(new ThreadStart(()=> await Download.file(uri)));
Thread myThread = new Thread(new ThreadStart(()=>Download.file(uri)));
myThread.Start();
myThread.Join();
class Download{
public static async void file(string url)
{
try
{
HttpWebRequest request;
HttpWebResponse webResponse = null;
request = HttpWebRequest.CreateHttp(url);
request.AllowReadStreamBuffering = true;
webResponse = await request.GetResponseAsync() as HttpWebResponse;
Stream responseStream = webResponse.GetResponseStream();
using (StreamReader reader = new StreamReader(responseStream))
{
string content = await reader.ReadToEndAsync();
}
webResponse.Close();
}
catch (Exception ex) {
Debug.WriteLine(ex.Message);
}
}
}
Thanks
You should make your file method (which is badly named, by the way - it should probably be something like DownloadFileAsync) return Task instead of void.
Then you can await it.
However, it's not clear why you're starting this in a different thread anyway - the point of asynchrony is that you don't need to start a new thread. From another async method, you can just use:
await Download.file(uri);
(Of course the fact that the method isn't doing anything with the content is a little strange...)
You should also consider using HttpClient or WebClient, both of which have this behaviour already available.

Async HTTPWebrequest with Timeout

Environemnt : Windows CE / .NET Compact FrameWork 3.5.
I need some guidance in
1) Implementing a Timeout functionality for an Asynchronous Web request.
ThreadPool::RegisterWaitForSingleObject() is not available for .NetCf and I'm bit stuck.
2) How to determine if network itself is not avaialable?
Googling didn't help.
Note : ThreadPool::RegisterWaitForSingleObject is not available for .NET Compact FrameWork.
Here is my Async implementation:
void StartRequest ()
{
try
{
HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create("http://192.78.221.11/SomeFunc/excpopulatedept");
RqstState myRequestState = new RqstState();
myRequestState.request = myHttpWebRequest;
// Start the asynchronous request.
IAsyncResult result =
(IAsyncResult)myHttpWebRequest.BeginGetResponse(new AsyncCallback(RespCallback), myRequestState);
// Release the HttpWebResponse resource.
myRequestState.response.Close();
}
catch (WebException ex)
{
;
}
catch (Exception ex)
{
;
}
}
private void RespCallback(IAsyncResult asynchronousResult)
{
try
{
//State of request is asynchronous.
RqstState myRequestState = (RqstState)asynchronousResult.AsyncState;
HttpWebRequest myHttpWebRequest = myRequestState.request;
myRequestState.response = (HttpWebResponse)myHttpWebRequest.EndGetResponse(asynchronousResult);
// Read the response into a Stream object.
Stream responseStream = myRequestState.response.GetResponseStream();
myRequestState.streamResponse = responseStream;
// Begin the Reading of the contents of the HTML page and print it to the console.
IAsyncResult asynchronousInputRead = responseStream.BeginRead(myRequestState.BufferRead, 0, 1024, new AsyncCallback(ReadCallBack), myRequestState);
return;
}
catch (WebException e)
{
Console.WriteLine("\nRespCallback Exception raised!");
Console.WriteLine("\nMessage:{0}", e.Message);
Console.WriteLine("\nStatus:{0}", e.Status);
}
}
private void ReadCallBack(IAsyncResult asyncResult)
{
try
{
RqstState myRequestState = (RqstState)asyncResult.AsyncState;
Stream responseStream = myRequestState.streamResponse;
int read = responseStream.EndRead(asyncResult);
// Read the HTML page and then print it to the console.
if (read > 0)
{
myRequestState.requestData.Append(Encoding.ASCII.GetString(myRequestState.BufferRead, 0, read));
IAsyncResult asynchronousResult = responseStream.BeginRead(myRequestState.BufferRead, 0, 1024, new AsyncCallback(ReadCallBack), myRequestState);
return;
}
else
{
//Console.WriteLine("\nThe contents of the Html page are : ");
if (myRequestState.requestData.Length > 1)
{
string stringContent;
stringContent = myRequestState.requestData.ToString();
responseStream.Close();
}
catch (WebException e)
{
}
}
}
}
Thank you for your time.
To continue what Eric J commented on, you have myRequestState.response.Close() just before your catches. That's almost always going to throw an exception because either response will be null, or response won't be opened. This is because you are asynchronously calling BeginGetResponse and the callback you give it will likely not be called by the time the next line (response.close) is called. You'll want to fix that instead of just hiding the exceptions because you don't know why they occur.
In terms of a timeout, because you're dealing with something that doesn't inherently have a configurable timeout, you'll have to set a timer and simply close the connection at the end of the time-out. e.g.
HttpWebRequest myHttpWebRequest; // ADDED
Timer timer; // ADDED
private void StartRequest()
{
myHttpWebRequest = (HttpWebRequest)WebRequest.Create("http://192.78.221.11/SomeFunc/excpopulatedept");
RqstState myRequestState = new RqstState();
myRequestState.request = myHttpWebRequest;
timer = new Timer(delegate { if (!completed) myHttpWebRequest.Abort(); }, null, waitTime, Timeout.Infinite); // ADDED
// Start the asynchronous request.
IAsyncResult result =
(IAsyncResult)myHttpWebRequest.BeginGetResponse(new AsyncCallback(RespCallback), myRequestState);
}
//...
private void ReadCallBack(IAsyncResult asyncResult)
{
try
{
RqstState myRequestState = (RqstState)asyncResult.AsyncState;
Stream responseStream = myRequestState.streamResponse;
int read = responseStream.EndRead(asyncResult);
// Read the HTML page and then print it to the console.
if (read > 0)
{
myRequestState.requestData.Append(Encoding.ASCII.GetString(myRequestState.BufferRead, 0, read));
IAsyncResult asynchronousResult = responseStream.BeginRead(myRequestState.BufferRead, 0, 1024, new AsyncCallback(ReadCallBack), myRequestState);
}
else
{
completed = true; // ADDED
using(timer) // ADDED
{
timer = null;
}
if (myRequestState.requestData.Length > 1)
{
string stringContent;
stringContent = myRequestState.requestData.ToString();
responseStream.Close();
}
}
}
}
I only copy and pasted your code, so it's as likely to compile as what you originally provided, but there should be enough there you get in going in the right direction.

Uploading HTTP progress tracking

I've got WPF application I'm writing that posts files to one of social networks.
Upload itself working just fine, but I'd like to provide some indication of how far along I am with the uploading.
I tried a bunch of ways to do this:
1) HttpWebRequest.GetStream method:
using (
var FS = File.Open(
localFilePath, FileMode.Open, FileAccess.Read, FileShare.Read))
{
long len = FS.Length;
HttpWebRequest request = (HttpWebRequest) WebRequest.Create(url);
request.Method = "POST";
request.ProtocolVersion = HttpVersion.Version11;
request.ContentType = "multipart/form-data; boundary=--AaB03x";
//predata and postdata is two byte[] arrays, that contains
//strings for MIME file upload (defined above and is not important)
request.ContentLength = predata.Length + FS.Length + postdata.Length;
request.AllowWriteStreamBuffering = false;
using (var reqStream = request.GetRequestStream())
{
reqStream.Write(predata, 0, predata.Length);
int bytesRead = 0;
int totalRead = 0;
do
{
bytesRead = FS.Read(fileData, 0, MaxContentSize);
totalRead += bytesRead;
reqStream.Write(fileData, 0, bytesRead);
reqStream.Flush(); //trying with and without this
//this part will show progress in percents
sop.prct = (int) ((100*totalRead)/len);
} while (bytesRead > 0);
reqStream.Write(postdata, 0, postdata.Length);
}
HttpWebResponse responce = (HttpWebResponse) request.GetResponse();
using (var respStream = responce.GetResponseStream())
{
//do things
}
}
2) WebClient way (much shorter):
void UploadFile (url, localFilePath)
{
...
WebClient client = new WebClient();
client.UploadProgressChanged += new UploadProgressChangedEventHandler(UploadPartDone);
client.UploadFileCompleted += new UploadFileCompletedEventHandler(UploadComplete);
client.UploadFileAsync(new Uri(url), localFilePath);
done.WaitOne();
//do things with responce, received from UploadComplete
JavaScriptSerializer jssSer = new JavaScriptSerializer();
return jssSer.Deserialize<UniversalJSONAnswer>(utf8.GetString(UploadFileResponce));
//so on...
...
}
void UploadComplete(object sender, UploadFileCompletedEventArgs e)
{
UploadFileResponce=e.Result;
done.Set();
}
void UploadPartDone(object sender, UploadProgressChangedEventArgs e)
{
//this part expected to show progress
sop.prct=(int)(100*e.BytesSent/e.TotalBytesToSend);
}
3) Even TcpClient way:
using (
var FS = File.Open(
localFilePath, FileMode.Open, FileAccess.Read, FileShare.Read))
{
long len = FS.Length;
long totalRead = 0;
using (var client = new TcpClient(urli.Host, urli.Port))
{
using (var clearstream = client.GetStream())
{
using (var writer = new StreamWriter(clearstream))
using (var reader = new StreamReader(clearstream))
{
//set progress to 0
sop.prct = 0;
// Send request headers
writer.WriteLine("POST " + urli.AbsoluteUri + " HTTP/1.1");
writer.WriteLine("Content-Type: multipart/form-data; boundary=--AaB03x");
writer.WriteLine("Host: " + urli.Host);
writer.WriteLine("Content-Length: " + (predata.Length + len + postdata.Length).ToString());
writer.WriteLine();
//some data for MIME
writer.Write(utf8.GetString(predata));
writer.Flush();
int bytesRead;
do
{
bytesRead = FS.Read(fileData, 0, MaxContentSize);
totalRead += bytesRead;
writer.BaseStream.Write(fileData, 0, bytesRead);
writer.BaseStream.Flush();
sop.prct = (int) ((100*totalRead)/len);
} while (bytesRead > 0)
writer.Write(utf8.GetString(postdata));
writer.Flush();
//read line of response and do other thigs...
respStr = reader.ReadLine();
...
}
}
}
}
In all cases the file was successfully sent to the server.
But always progress looks like this: for a few seconds it runs from 0 to 100 and then waits until file actually uploading (about 5 minutes - file is 400MB).
So I think the data from a file is buffered somewhere and I'm tracking not uploading, but buffering data. And then must wait until it's uploaded.
My questions are:
1) Is there any way to track actual uploading data? That the method Stream.Write() or Flush() (which as I read somewhere, does not work for NetworkStream) did not return until it receives confirmation from the server that the TCP packets received.
2) Or can I deny buffering (AllowWriteStreamBUffering for HttpWebRequest doesn't work)?
3) And does it make sense to go further "down" and try with Sockets?
updated:
To avoid any doubts in the way of progress displaying on UI, I rewrote the code to log a file.
so, here is code:
using (var LogStream=File.Open("C:\\123.txt",FileMode.Create,FileAccess.Write,FileShare.Read))
using (var LogWriter=new StreamWriter(LogStream))
using (var FS = File.Open(localFilePath, FileMode.Open, FileAccess.Read, FileShare.Read))
{
long len = FS.Length;
HttpWebRequest request = (HttpWebRequest) WebRequest.Create(url);
request.Timeout = 7200000; //2 hour timeout
request.Method = "POST";
request.ProtocolVersion = HttpVersion.Version11;
request.ContentType = "multipart/form-data; boundary=--AaB03x";
//predata and postdata is two byte[] arrays, that contains
//strings for MIME file upload (defined above and is not important)
request.ContentLength = predata.Length + FS.Length + postdata.Length;
request.AllowWriteStreamBuffering = false;
LogWriter.WriteLine(DateTime.Now.ToString("o") + " Start write into request stream. ");
using (var reqStream = request.GetRequestStream())
{
reqStream.Write(predata, 0, predata.Length);
int bytesRead = 0;
int totalRead = 0;
do
{
bytesRead = FS.Read(fileData, 0, MaxContentSize);
totalRead += bytesRead;
reqStream.Write(fileData, 0, bytesRead);
reqStream.Flush(); //trying with and without this
//sop.prct = (int) ((100*totalRead)/len); //this part will show progress in percents
LogWriter.WriteLine(DateTime.Now.ToString("o") + " totalRead= " + totalRead.ToString() + " / " + len.ToString());
} while (bytesRead > 0);
reqStream.Write(postdata, 0, postdata.Length);
}
LogWriter.WriteLine(DateTime.Now.ToString("o") + " All sent!!! Waiting for responce... ");
LogWriter.Flush();
HttpWebResponse responce = (HttpWebResponse) request.GetResponse();
LogWriter.WriteLine(DateTime.Now.ToString("o") + " Responce received! ");
using (var respStream = responce.GetResponseStream())
{
if (respStream == null) return null;
using (var streamReader = new StreamReader(respStream))
{
string resp = streamReader.ReadToEnd();
JavaScriptSerializer jssSer = new JavaScriptSerializer();
return jssSer.Deserialize<UniversalJSONAnswer>(resp);
}
}
}
and here is result (I cut the middle):
2011-11-19T22:00:54.5964408+04:00 Start write into request stream.
2011-11-19T22:00:54.6404433+04:00 totalRead= 1048576 / 410746880
2011-11-19T22:00:54.6424434+04:00 totalRead= 2097152 / 410746880
2011-11-19T22:00:54.6434435+04:00 totalRead= 3145728 / 410746880
2011-11-19T22:00:54.6454436+04:00 totalRead= 4194304 / 410746880
2011-11-19T22:00:54.6464437+04:00 totalRead= 5242880 / 410746880
2011-11-19T22:00:54.6494438+04:00 totalRead= 6291456 / 410746880
.......
2011-11-19T22:00:55.3434835+04:00 totalRead= 408944640 / 410746880
2011-11-19T22:00:55.3434835+04:00 totalRead= 409993216 / 410746880
2011-11-19T22:00:55.3464837+04:00 totalRead= 410746880 / 410746880
2011-11-19T22:00:55.3464837+04:00 totalRead= 410746880 / 410746880
2011-11-19T22:00:55.3464837+04:00 All sent!!! Waiting for responce...
2011-11-19T22:07:23.0616597+04:00 Responce received!
as you can see program thinks that it uploaded ~400MB for about 2 seconds. And after 7 minutes file actually uploads and I receive responce.
updated again:
Seems to this is happening under WIndows 7 (not shure about x64 or x86).
When I run my code uder XP everything works perfectly and progress is shown absolute correctly
it's more than year since this question was posted, but I think my post can be usefull for someone.
I had the same problem with showing progress and it behaved exactly like you described. So i decided to use HttpClient which shows upload progress correctly. Then I've encountered interesting bug - when I had Fiddler launched HttpClient started to show its upload progress in unexpected way like in WebClient/HttpWebRequest above so I thinked maybe that was a problem of why WebClient showed upload progres not correctly (I think I had it launched). So I tried with WebClient again (without fiddler-like apps launched) and all works as it should, upload progress has correct values. I have tested in on several PC with win7 and XP and in all cases progress was showing correctly.
So, I think that such program like Fiddler (probably not only a fiddler) has some affect on how WebClient and other .net classes shows upload progress.
this discussion approves it:
HttpWebRequest doesn't work except when fiddler is running
You could use the WebClient's UploadFile to upload file rather than using writing file as a file stream. In order to track the percentage of the data received and uploaded you can use UploadFileAsyn and subscribe to its events.
In the code bellow I've used UploadFileAsyn to the upload files synchronously, but it need not to be synchronous as far as you don't dispose the instance of the uploader.
class FileUploader : IDisposable
{
private readonly WebClient _client;
private readonly Uri _address;
private readonly string _filePath;
private bool _uploadCompleted;
private bool _uploadStarted;
private bool _status;
public FileUploader(string address, string filePath)
{
_client = new WebClient();
_address = new Uri(address);
_filePath = filePath;
_client.UploadProgressChanged += FileUploadProgressChanged;
_client.UploadFileCompleted += FileUploadFileCompleted;
}
private void FileUploadFileCompleted(object sender, UploadFileCompletedEventArgs e)
{
_status = (e.Cancelled || e.Error == null) ? false : true;
_uploadCompleted = true;
}
private void FileUploadProgressChanged(object sender, UploadProgressChangedEventArgs e)
{
if(e.ProgressPercentage % 10 == 0)
{
//This writes the pecentage data uploaded and downloaded
Console.WriteLine("Send: {0}, Received: {1}", e.BytesSent, e.BytesReceived);
//You can have a delegate or a call back to update your UI about the percentage uploaded
//If you don't have the condition (i.e e.ProgressPercentage % 10 == 0 )for the pecentage of the process
//the callback will slow you upload process down
}
}
public bool Upload()
{
if (!_uploadStarted)
{
_uploadStarted = true;
_client.UploadFileAsync(_address, _filePath);
}
while (!_uploadCompleted)
{
Thread.Sleep(1000);
}
return _status;
}
public void Dispose()
{
_client.Dispose();
}
}
Client Code:
using (FileUploader uploader = new FileUploader("http://www.google.com", #"C:\test.txt"))
{
uploader.Upload();
}
You can register a custom callback (may be a delegate) on the FileUploadProgressChanged event handler to update your WPF UI.
The upload progress changed event get called more often if your callback for the event does any IO then that'll slowdown the download progress. It's best to have infrequent update e.g. the following code update only evey 10% up.
private int _percentageDownloaded;
private void FileUploadProgressChanged(object sender, UploadProgressChangedEventArgs e)
{
if (e.ProgressPercentage % 10 == 0 && e.ProgressPercentage > _percentageDownloaded)
{
_percentageDownloaded = e.ProgressPercentage;
//Any callback instead of printline
Console.WriteLine("Send: {0} Received: {1}", e.BytesSent, e.BytesReceived);
}
}
my suggestion is to use new HTTPClient class (available in .NET 4.5). It supports progress.
This article helped me a lot with this:
http://www.strathweb.com/2012/06/drag-and-drop-files-to-wpf-application-and-asynchronously-upload-to-asp-net-web-api/
My code for upload file:
private void HttpSendProgress(object sender, HttpProgressEventArgs e)
{
HttpRequestMessage request = sender as HttpRequestMessage;
Console.WriteLine(e.BytesTransferred);
}
private void Window_Loaded_1(object sender, RoutedEventArgs e)
{
ProgressMessageHandler progress = new ProgressMessageHandler();
progress.HttpSendProgress += new EventHandler<HttpProgressEventArgs>(HttpSendProgress);
HttpRequestMessage message = new HttpRequestMessage();
StreamContent streamContent = new StreamContent(new FileStream("e:\\somefile.zip", FileMode.Open));
message.Method = HttpMethod.Put;
message.Content = streamContent;
message.RequestUri = new Uri("{Here your link}");
var client = HttpClientFactory.Create(progress);
client.SendAsync(message).ContinueWith(task =>
{
if (task.Result.IsSuccessStatusCode)
{
}
});
}
This one has been bugging me for at least one day. I have started with using WebClient.UploadFileAsync, next tried the ProgressMessageHandler for HttpClient then rolled my own HttpContent for the HttpClient API. None of those approaches worked (for me).
It appears HttpWebRequest, which sits at the bottom of most (all?) .NET Http abstraction like WebClient and HttpClient, buffers the request and response stream by default, which I confirmed by looking at it in ILSpy.
As others have noted, you can make your request use chunked encoding one way or another which will effectively disable buffering the request stream, but still this is not going to fix the progress reporting.
I found that it was necessary to flush the request stream after each block that I send in order to accurately reflect sending progress, or else your data will simply be buffered one step further down the pipeline (probably somewhere in NetworkStream or OS, didn't check). The sample code below works for me and also does a minimalistic job at translating back from a HttpWebResponse to HttpResponseMessage (which you may not need, YMMV).
public async Task<HttpResponseMessage> UploadFileAsync( string uploadUrl, string absoluteFilePath, Action<int> progressPercentCallback )
{
var length = new FileInfo( absoluteFilePath ).Length;
var request = new HttpWebRequest( new Uri(uploadUrl) ) {
Method = "PUT",
AllowWriteStreamBuffering = false,
AllowReadStreamBuffering = false,
ContentLength = length
};
const int chunkSize = 4096;
var buffer = new byte[chunkSize];
using (var req = await request.GetRequestStreamAsync())
using (var readStream = File.OpenRead(absoluteFilePath))
{
progressPercentCallback(0);
int read = 0;
for (int i = 0; i < length; i += read)
{
read = await readStream.ReadAsync( buffer, 0, chunkSize );
await req.WriteAsync( buffer, 0, read );
await req.FlushAsync(); // flushing is required or else we jump to 100% very fast
progressPercentCallback((int)(100.0 * i / length));
}
progressPercentCallback(100);
}
var response = (HttpWebResponse)await request.GetResponseAsync();
var result = new HttpResponseMessage( response.StatusCode );
result.Content = new StreamContent( response.GetResponseStream() );
return result;
}
At fast guess, you are running this code on UI thread. You need to run upload stuff on new thread.
At that point you have 2 options. 1) You run timer on UI thread and update UI. 2) You update UI using Invoke(because you can't access UI from another thread) calls to update UI.
In the first example I think your progress bar is showing how fast you write into the stream from the file on disk - not the actual upload progress (which is why it all happens to 100% really quickly then the upload chugs on*).
I might be wrong ^^ and have no WPF experience but I have uploaded massive files from Silverlight to WCF and the model used there is (as you do) to break up the file into blocks. Send each block. When you get a response from the server ("block 26 received ok"), update the progress bar as really, you can't (or should not) update the progress bar unless you /know/ that block x made it - and a good way to know that is if the server says it got it.
*I wish I could upload 400Mb in 5 mins. Would take me all day...
I had the same problem. I spent a lot of time and solved the problem as follows:
Antivirus AVAST. When I turn it off my program works perfectly...

WP7 app never exits BeginGetResponse and goes into the callback function

I have the following code:
private void GetRequestStreamCallback(IAsyncResult asynchronousResult)
{
HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
// End the operation
Stream postStream = request.EndGetRequestStream(asynchronousResult);
//Console.WriteLine("Please enter the input data to be posted:");
//string postData = Console.ReadLine();
string postData = "my data";
// Convert the string into a byte array.
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
// Write to the request stream.
postStream.Write(byteArray, 0, postData.Length);
postStream.Close();
// Start the asynchronous operation to get the response
IAsyncResult result =
(IAsyncResult)request.BeginGetResponse(new AsyncCallback(GetResponseCallback), request);
}
private void GetResponseCallback(IAsyncResult asynchronousResult)
{
HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
// End the operation
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asynchronousResult);
Stream streamResponse = response.GetResponseStream();
StreamReader streamRead = new StreamReader(streamResponse);
string responseString = streamRead.ReadToEnd();
Console.WriteLine(responseString);
// Close the stream object
streamResponse.Close();
streamRead.Close();
// Release the HttpWebResponse
response.Close();
allDone.Set();
Dispatcher.BeginInvoke((Action)(() => Debug.WriteLine("George")));
}
However when my code hits BeginGetResponse it never exits (and I do not hit a breakpoint in the GetResponseCallback function). I tried adding the BeginInvoke call, but I still never enter this method. This code works in a windows console app - it's on Windows Phone 7 that it doesn'teorg
Can anyone see what I am doing wrong?
Thanks.
If you have created the HttpWebRequest on the UI thread, then make sure you don't block the UI thread, otherwise you can deadlock.
The sample from the desktop .NET you have linked isn't optimized for the current phone networking stack. You should change the code so that you create the HttpWebRequest on a background thread.
I can't see what's wrong with your code (maybe a complete example of what you're trying to do may help) but here's a simple working example of a way of performing the action you want to do.
It posts some data to a URI and then passes the repsonse to a callback function:
Simply execute like this (use of a BackgroundWorker is not necessary but is recommended)
var bw = new BackgroundWorker();
bw.DoWork += (o, args) => PostDataToWebService("http://example.com/something", "key=value&key2=value2", MyCallback);
bw.RunWorkerAsync();
Here's the callback function it refers to:
(You can change this however is appropriate to your needs.)
public static void MyCallback(string aString, Exception e)
{
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
if (e == null)
{
// aString is the response from the web server
MessageBox.Show(aString, "success", MessageBoxButton.OK);
}
else
{
MessageBox.Show(e.Message, "error", MessageBoxButton.OK);
}
});
}
Here's the actual method:
public void PostDataToWebService(string url, string data, Action<string, Exception> callback)
{
if (callback == null)
{
throw new Exception("callback may not be null");
}
try
{
var uri = new Uri(url, UriKind.Absolute);
var req = HttpWebRequest.CreateHttp(uri);
req.ContentType = "application/x-www-form-urlencoded";
req.Method = "POST";
AsyncCallback GetTheResponse = ar =>
{
try
{
var result = ar.GetResponseAsString();
callback(result, null);
}
catch (Exception ex)
{
callback(null, ex);
}
};
AsyncCallback SetTheBodyOfTheRequest = ar =>
{
var request = ar.SetRequestBody(data);
request.BeginGetResponse(GetTheResponse, request);
};
req.BeginGetRequestStream(SetTheBodyOfTheRequest, req);
}
catch (Exception ex)
{
callback(null, ex);
}
}
and here are the extension/helper methods it uses:
public static class IAsyncResultExtensions
{
public static string GetResponseAsString(this IAsyncResult asyncResult)
{
string responseString;
var request = (HttpWebRequest)asyncResult.AsyncState;
using (var resp = (HttpWebResponse)request.EndGetResponse(asyncResult))
{
using (var streamResponse = resp.GetResponseStream())
{
using (var streamRead = new StreamReader(streamResponse))
{
responseString = streamRead.ReadToEnd();
}
}
}
return responseString;
}
public static HttpWebRequest SetRequestBody(this IAsyncResult asyncResult, string body)
{
var request = (HttpWebRequest)asyncResult.AsyncState;
using (var postStream = request.EndGetRequestStream(asyncResult))
{
using (var memStream = new MemoryStream())
{
var content = body;
var bytes = System.Text.Encoding.UTF8.GetBytes(content);
memStream.Write(bytes, 0, bytes.Length);
memStream.Position = 0;
var tempBuffer = new byte[memStream.Length];
memStream.Read(tempBuffer, 0, tempBuffer.Length);
postStream.Write(tempBuffer, 0, tempBuffer.Length);
}
}
return request;
}
}

Help threading HttpWebRquest in c#

Hi guys just wondering if somebody could help me try and correctly thread my application, I am constantly hitting an hurdle after another, I have never been to clued up on threading in applications. I have tryed following this http://www.developerfusion.com/code/4654/asynchronous-httpwebrequest/ tutorial.
basically I'm just trying to stop my request from hanging my application
public class Twitter
{
private const string _username = "****",
_password = "****";
private WebResponse webResp;
public string getTimeLine()
{
Thread thread = new Thread(new ThreadStart(TwitterRequestTimeLine));
thread.IsBackground = true;
thread.Start();
using (Stream responseStream = webResp.GetResponseStream())
{
//
using (StreamReader reader = new StreamReader(responseStream))
{
return reader.ReadToEnd();
}
}
}
private void TwitterRequestTimeLine()
{
string aUrl = "http://168.143.162.116/statuses/home_timeline.xml";
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(aUrl);
SetRequestParams(request);
request.Credentials = new NetworkCredential(_username, _password);
//WebResponse tempResp = request.GetResponse();
ThreadState state = new ThreadState();
IAsyncResult result = request.BeginGetResponse(new AsyncCallback(???), ???);
}
private static void SetRequestParams( HttpWebRequest request )
{
request.Timeout = 500000;
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.UserAgent = "AdverTwitment";
}
}
}
anyone help would be greatly appricated
You really don't need to thread HttpWebRequest.
When you use BeginGetResponse() and EndGetResponse() with HttpWebRequest, it already uses a background thread for you in order to work asynchronously. There is no reason to push this into a background thread.
As for usage: The help for HttpWebRequest.BeginGetResponse demonstrates a complete, asynchronous request.
If this is a WinForms app, the easiest way to keep the GUI responsive while executing the WebRequest is to use a BackgroundWorker component. Drop a BackgroundWorker on your form and call its RunWorkAsync() method. Put the code to execute the WebRequest and read the Response in the DoWork event handler.
Try using an AsyncCallback like Rubens suggested but have the callback call into a separate method to load the data to its destination. If the getTimeline method doesn't return immediately it will cause the application to hang, because the UI Thread is what is running the request itself.
If you use a separate AsyncCallback to be called after the request is done and have it load the data then the method will return immediately and your UI thread can do other things while it waits.
What about this:
private string getTimeLine()
{
string responseValue = "";
string aUrl = "http://168.143.162.116/statuses/home_timeline.xml";
AutoResetEvent syncRequest = new AutoResetEvent(false);
WebRequest request = WebRequest.Create(aUrl);
request.Method = "POST";
request.BeginGetResponse(getResponseResult =>
{
HttpWebResponse response =
(HttpWebResponse)request.EndGetResponse(getResponseResult);
using (StreamReader reader =
new StreamReader(response.GetResponseStream()))
{
responseValue = reader.ReadToEnd();
}
syncRequest.Set();
}, null);
syncRequest.WaitOne();
return responseValue;
}
EDIT: Ok, I tried to keep a method returning a string, that's why I used AutoResetEvent; If you use a BackgroundWorker, you'll get notified when your data is available:
BackgroundWorker worker = new BackgroundWorker();
string responseValue = "";
worker.RunWorkerCompleted += (sender, e) =>
{
// update interface using responseValue variable
};
worker.DoWork += (sender, e) =>
{
string aUrl = "http://168.143.162.116/statuses/home_timeline.xml";
WebRequest request = WebRequest.Create(aUrl);
// .. setup
using(StreamReader reader =
new StreamReader(request.GetResponse().GetResponseStream()))
responseValue = reader.ReadToEnd();
};
worker.RunWorkerAsync();

Categories