Asynchronous call, but not really

T

tcomer

Hello,

I'm working on an application that grabs some data from the web via
HttpWebRequest. I'm using a local objects method to get the data, but
the problem is that my form doesn't load until this method has
finished what it's doing.. which takes about 10-15 seconds. Here is
what I have:

Using System.Threading;

public class MyClass{
private MyObject mynewobject= new MyObject();
...
private delegate void GetDataDelegate(string url);

public MyClass(){
InitalizeComponent();
GetWebData(); // <- form isn't visible until after this
returns
this.lblStatus.Text = "finished";
}

private GetWebData(){
GetDataDelegate gdd = new
GetDataDelegate(mynewobject.RetrieveData);

// Initiate the asynchronous call
IAsyncResult ar = gdd.BeginInvoke("http://www.whatever.com/
file.txt", null, null);
Thread.Sleep(0);
this.lblStatus.Text = "getting data";
mld.EndInvoke(ar);
}
}

Again, what's happening is that the application starts, but I get no
visual cue that it has started, until after the GetWebData() call has
returned, sometimes it takes up to 30 seconds. I need the form and
components to be loaded first, but I'd also like to be pulling data as
soon as the program runs. What am I doing wrong? Thanks
 
J

Jon Skeet [C# MVP]

Again, what's happening is that the application starts, but I get no
visual cue that it has started, until after the GetWebData() call has
returned, sometimes it takes up to 30 seconds. I need the form and
components to be loaded first, but I'd also like to be pulling data as
soon as the program runs. What am I doing wrong? Thanks

You're calling EndInvoke, which will wait until GetData returns. So
yes, you're doing things asynchronously - but you're not actually
achieving any benefits.

Instead of calling EndInvoke, specify a callback in the call to
BeginInvoke so that your UI thread will be free while the web request
is fetching data.

Jon
 
N

Nicholas Paldino [.NET/C# MVP]

Well, technically, the form doesn't show until after the constructor is
called. It's just that what you do after the call to GetWebData is so quick
that it isn't perceptable (there are also some other calls that are made
under the covers).

As for what is causing your problem, you are calling the request
asynchronously, but you are then calling EndInvoke right after. EndInvoke
will block until the call is complete.

The call to Sleep doesn't do anything useful in this case, btw.

What you need to do is pass a delegate to the BeginInvoke method which
will get executed when the call is complete. Then call EndInvoke in that
method, and you will then be able to access your data.

You would have to make sure that if you are updating the UI though, you
are doing so by calling Invoke on the control, as your callback will not be
executed on the UI thread.
 
T

tcomer

You're calling EndInvoke, which will wait until GetData returns. So
yes, you're doing things asynchronously - but you're not actually
achieving any benefits.

Instead of calling EndInvoke, specify a callback in the call to
BeginInvoke so that your UI thread will be free while the web request
is fetching data.

Jon

That makes complete sense now that you pointed it out, funny how that
works :) Exactly what I was looking for, thanks a lot.
 
T

tcomer

Thanks for the help.. I think I've got it figured out.

Although, I do have one other question. Hopefully someone could just
point me in the right direction.

Within the asynchronous call, I'd like to start one other thread that
will Start, process a chunk of data, update the datagrid and then
return to get another chunk of data(I'm not going thread-happy here,
trust me). Basically, when the data is being retrieved.. my datagrid
should be updating as the application receives the data. Could someone
please point me in the right direction? I'm a newbie when it comes to
threading.. sorta.
 
N

Nicholas Paldino [.NET/C# MVP]

To update information on the UI thread, you should look at the
documentation for the Invoke method on the Control class. It is used to
pass a delegate to the UI thread to process. You need to do this because
you can not make updates to the UI thread from another thread, just the UI
thread.

If the data is bound to a UI component, then you are going to have to
make the call to update the bound object through a call to Invoke.
 
P

Peter Duniho

Within the asynchronous call, I'd like to start one other thread that
will Start, process a chunk of data, update the datagrid and then
return to get another chunk of data(I'm not going thread-happy here,
trust me). Basically, when the data is being retrieved.. my datagrid
should be updating as the application receives the data. Could someone
please point me in the right direction? I'm a newbie when it comes to
threading.. sorta.

As Nicholas says, you'll need to use Control.Invoke() to actually update
your user interface. Other than that, it's simply a matter of organizing
the processing logic so that it does things when you want it to.

On that topic, while you're not specific about how you're doing your i/o,
it's likely at some point you're using a built-in class that already has
an asynchronous API. If so, it'd be my recommendation that you forget
doing any threading yourself, whether explicitly starting a new thread or
using the thread pool via the Delegate.BeginInvoke() method. Instead, it
would be better to just write the data-handling class so that it's using
the asynchronous API on the i/o class you're using. You can code it to
call the "Begin..." to start retrieval of a "chunk of data", then when
that chunk completes you update your UI to reflect the data and start
another chunk, again with a call to "Begin...".

IMHO, this is much cleaner than creating a bunch of threads and managing
it yourself. This is especially true given the apparent flow of data
through your logic that you've described here.

Pete
 

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