Cross-Thread Issue with HTTPWebRequest.EndGetResponse()

B

Buju

Hi,

I have to port a Windows Forms Application (.NET 2.0) to a Windows
Mobile 5.0 Application (.NET CF 2.0).

On the desktop application, we used System.Net.WebClient class to
communicate with our webserver. But all of you know WebClient is not
supported in Compact Framework 2.0. So I decided to simple reimplement
only the necessary methods I need using HTTPWebRequest and
HTTPWebResponse: DownloadStringAsync(), UploadStringAsync(),
UploadStringCompleted, DownloadStringCompleted. My completed
eventhandlers will then update some UI controls are called:
HandleDownloadStringCompleted, HandleUploadStringCompleted

The problem is when the download has finished and I call
HandleDownloadStringCompleted() to update the UI, I get an
InvalidOperationException because I'm still in the async thread from
HTTPWebRequest.EndGetResponse() and not the main thread.

My question is, how can I call a main thread method from worker thread?
I have no reference to the windows form, therefore I can't use
Control.Invoke(). --> WebClient also didn't has it. So how did
WebClient managed to call a main thread method (delegate
DownLoadStringCompleted)?

Code snipplet, I will only show the DownloadStringAsync:

// a simple reimplementation from .NET 2.0 class
public class DownloadStringCompletedEventArgs : EventArgs
{
private string m_result;
private Exception m_exception;
private bool m_cancelled;
private Object m_userState;

public string Result { get { return m_result; } set { m_result =
value; } }
public Exception Error { get { return m_exception; } set {
m_exception = value; } }
public bool Cancelled { get { return m_cancelled; } set {
m_cancelled = value; } }
public Object UserState { get { return m_userState; } set {
m_userState = value; } }
}

//--------------------------------------------------------------------------------
public class MyWebClient {
public delegate void DownloadStringCompletedEventHandler(object
sender, DownloadStringCompletedEventArgs e);
public delegate void UploadStringCompletedEventHandler(object
sender, UploadStringCompletedEventArgs e);

public event DownloadStringCompletedEventHandler
DownloadStringCompleted;
public event UploadStringCompletedEventHandler
UploadStringCompleted;

....

public void DownloadStringAsync(string address, object handler)
{

// Create a HttpWebrequest object to the desired URL.
HttpWebRequest myHttpWebRequest =
(HttpWebRequest)WebRequest.Create(address);

// MyRequestState is an object to pass through AsyncCallback
MyRequestState myRequestState = new MyRequestState();
myRequestState.request = myHttpWebRequest;
myRequestState.handler = handler;

// Start the asynchronous request.
IAsyncResult result =
(IAsyncResult)myHttpWebRequest.BeginGetResponse(new
AsyncCallback(RespCallback), myRequestState);

}


//--------------------------------------------------------------------------------
private void RespCallback(IAsyncResult asynchronousResult)
{
DownloadStringCompletedEventArgs eventArgs = new
DownloadStringCompletedEventArgs();
MyRequestState myRequestState = null;
try
{
// State of request is asynchronous.
myRequestState = (RequestState)asynchronousResult.AsyncState;
myRequestState.eventArgs = eventArgs;
eventArgs.UserState = myRequestState.handler;

HttpWebRequest myHttpWebRequest = myRequestState.request;
myRequestState.response =
(HttpWebResponse)myHttpWebRequest.EndGetResponse(asynchronousResult);

StreamReader loResponseStream = new
StreamReader(myRequestState.response.GetResponseStream());

eventArgs.Result = loResponseStream.ReadToEnd();

loResponseStream.Close();
myRequestState.response.Close();

}
catch (WebException e)
{
if (myRequestState.response != null)
myRequestState.response.Close();
eventArgs.Error = e;
}
finally
{
eventArgs.UserState = myRequestState.handler;
HandleDownloadStringCompleted(this, eventArgs);
}
}


//--------------------------------------------------------------------------------
private void HandleDownloadStringCompleted(object sender,
DownloadStringCompletedEventArgs e)
{
if (DownloadStringCompleted != null)
{
// call HandleDownloadStringCompleted from MyClient
DownloadStringCompleted(sender, e);
}
}

....

} // MyWebClient

//--------------------------------------------------------------------------------
public class MyClient {

....

private static string Method1(string url, RunCompletedEventHandler
handler) {

...

MyWebClient client = new MyWebClient();
client.DownloadStringCompleted += new
MyWebClient.DownloadStringCompletedEventHandler(HandleDownloadStringCompleted);

// call the async method
client.DownloadStringAsync(url, handler);

...
}


//--------------------------------------------------------------------------------
private static void HandleDownloadStringCompleted(object sender,
DownloadStringCompletedEventArgs e)
{
RunCompletedEventHandler handler =
(RunCompletedEventHandler)e.UserState;
if (e.Error != null) {
ShowErrorIfNotInternalServerError(e.Error);

handler(e.Error == null, null);
}
else {
// this will call a EventHandler to update the UI --> Exception
handler(e.Error == null, e.Result);
}
}

}
 
B

Buju

hmm ... wenn download has finished I call
HandleDownloadStringCompleted(this, eventArgs) in the method
RespCallback ... isn't this the event? or am I wrong?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top