views:

240

answers:

8

Hi, In order to avoid freezing of GUI, I wanted to run method connecting to DB asynchronously. Therefore I have written this:

DelegatLoginu dl = ConnectDB;
            IAsyncResult ar=dl.BeginInvoke(null, null);
            bool result = (bool)dl.EndInvoke(ar);

But it is still freezing and I do not understand why - I though BeginInvoke assures that method it references is run in another thread. Thank you!

+2  A: 

You're immediately blocking your UI thread when calling dl.EndInvoke(ar). This kind of defeats the whole purpose of having an async call.

Anton Gogolev
Well, it was mz guess..so what is this good for? I thought it does all the connection stuff in backround and then only returns :(
Petr
The `BeginXxx` returns just after the call, at which point the connection stuff is being handled in the background. When the result is ready, you'll get notified (either by a callback or by polling on the `WaitHandle` in the `IAsyncResult` returned by the `BeginXxx` call). At this point you invoke the `EndXxx` to retrieve the result (or get exceptions which happended in the call). Calling `EndXxx` early forces a wait until the result is ready.
Lucero
+9  A: 

Calling EndInvoke() will block until the BeginInvoke() call has completed.

You need this kind of pattern in order for your long-running method to invoke a callback when it finishes:

public void DemoCallback()
{
    MethodDelegate dlgt = new MethodDelegate (this.LongRunningMethod) ;
    string s ;
    int iExecThread;

    // Create the callback delegate.
    AsyncCallback cb = new AsyncCallback(MyAsyncCallback);

    // Initiate the Asynchronous call passing in the callback delegate
    // and the delegate object used to initiate the call.
    IAsyncResult ar = dlgt.BeginInvoke(3000, out iExecThread, cb, dlgt); 
}

public void MyAsyncCallback(IAsyncResult ar)
{
    string s ;
    int iExecThread ;

    // Because you passed your original delegate in the asyncState parameter
    // of the Begin call, you can get it back here to complete the call.
    MethodDelegate dlgt = (MethodDelegate) ar.AsyncState;

    // Complete the call.
    s = dlgt.EndInvoke (out iExecThread, ar) ;

    MessageBox.Show (string.Format ("The delegate call returned the string:   \"{0}\", 
                                and the number {1}", s, iExecThread.ToString() ) );
}
RickL
Do I need to use AsyncCallBack class or I can pass simple delegate?
Petr
It has to be an AsyncCallBack delegate, i.e. your function must look like the MyAsyncCallback() example above - return void, and take in IAsyncResult as a parameter.
RickL
+3  A: 

See the description of EndInvoke here, specifically:

The EndInvoke() function is used to retrieve the results of the asynchronous call. It can be called anytime after BeginInvoke(). If the asynchronous call has not completed yet, EndInvoke() blocks until it completes.

Chris Schmich
A: 

Specify a method to be called when the call is completed in BeginInvoke (like dl.BeginInvoke(null, OnConnectCompleted)). Then the thread will not be blocked.

JWL_
A: 

Why not just use a BackgroundWorker instead?

James
A: 

Call to EndInvoke will block your current thread. You should pass a delegate into the BeginInvoke instead of calling the EndInvoke

labadana
A: 

There's 4 different patterns to using the async model in .NET as this question covers very well.

You're using the "I'll call you" approach. However if you want to wait until the work item has finished, the best technique is to use a Mutex (the WaitHandle):

void Run()
{
    Action<string> doWork = DoWork;
    IAsyncResult result = doWork.BeginInvoke("I will call you", null, null);

    // You "call the method" - wait 10 seconds for the method to finish.
    bool success = result.AsyncWaitHandle.WaitOne(10 * 1000);
}

void DoWork()
{
}

I suspect you don't want to block, in which case "fire and forget" causes the least headaches.

Chris S
A: 

http://www.codeproject.com/KB/cs/AsyncMethodInvocation.aspx

this maybe useful

ligaoren