Reputation: 1823
I am using WCF Async methods.
I face issue when I try to return the value of the callback function.
What are the possible methods of solution? (using .net 4.0, but not 4.5)
public static Object LoadInfo()
{
var service = new SomeWcfService();
service.BeginGetInfo(CallbackMethod, service);
// HOW TO GET INFROMATION FROM CALLBACK??
return INFORMATION;
}
private static void CallbackMethod(IAsyncResult ar)
{
// HOW TO PASS INFROMATION TO LoadInfo??
var INFORMATION = (ar.AsyncState as SomeWcfService).EndGetInfo(ar);
}
Note: All work should be asynchronously.
Thanks.
Upvotes: 1
Views: 3226
Reputation: 2698
Understanding async at first, especially with callbacks is tough. In your example you make an incorrect, but natural assumption...
public static Object LoadInfo()
{
var service = new SomeWcfService();
service.BeginGetInfo(CallbackMethod, service);
// HOW TO GET INFROMATION FROM CALLBACK??
// ERROR: You assume you have more work to do in this method,
// or that this is the place to return your results.
return INFORMATION;
}
The method you give below, is where the work occurs after your results are returned:
private static void CallbackMethod(IAsyncResult ar)
{
// HOW TO PASS INFROMATION TO LoadInfo??
// OOPS! No need to pass pack to LoadInfo - it's done...
var INFORMATION = (ar.AsyncState as SomeWcfService).EndGetInfo(ar);
}
Instead you will want something like this
public static void LoadInfo()
{
var service = new SomeWcfService();
// begin an asynchronous service call
// and handle the results in another method, "CallbackMethod"
service.BeginGetInfo(CallbackMethod, service);
// You can do other, non-service related,
// things here while the service call executes
}
Then your other method handles all the results:
private static void CallbackMethod(IAsyncResult ar)
{
var results = (ar.AsyncState as SomeWcfService).EndGetInfo(ar);
// Do whetever you need with results here
}
As Will pointed out in his excelent answer (+1, as if he needs it lol!), instead of having a separate call-back method, you can use an anonymous method with a lambda expression like:
public static void LoadInfo()
{
var service = new SomeWcfService();
// begin an asynchronous service call
// and handle the results in this anonymous method
service.BeginGetInfo(x =>
{
// B. This code block will be called when the service returns with results
var results = (ar.AsyncState as SomeWcfService).EndGetInfo(ar);
// Do whetever you need with results here
}, service);
// A. You can do other things here while the service call executes
// but debugging this gets more complicated because things will likely
// occur at A before they occur at B
}
So, the over-all mentality of Asynchronous is:
Upvotes: 1
Reputation:
Better you design to use the async pattern than fight against it.
But, if you must access an async method synchronously, you can use a semaphore to block the calling thread until the async method returns.
public static Object LoadInfo()
{
// this is our semaphore
var blocker = new AutoResetEvent();
object result = null;
var service = new SomeWcfService();
// use a lambda instead of a method as the callback.
// this will result in a closure where we can access the result and blocker variables
service.BeginGetInfo(x =>
{
// We are on a different thread within this lambda
result = (x.AsyncState as SomeWcfService).EndGetInfo(ar);
// release anybody calling blocker.WaitOne
blocker.Set();
}, service);
// we are still on the original thread here, and
// BeginGetInfo has possibly not yet executed, so we must wait until Set is called
blocker.WaitOne(Timeout.Infinite);
return result;
}
This is rarely a good design choice. Aynchornous patterns are much better for responsive UI. Better to do something like this
public void LoadInfo()
{
// Makes the UI show a loading indicator, blocking all actions except for CANCEL
LoadingInfo = true;
var service = new SomeWcfService();
service.BeginGetInfo(CallbackMethod, service);
}
private void CallbackMethod(IAsyncResult ar)
{
// the UI is now released from loading
LoadingInfo = false;
// the UI is triggered to show our data
ViewModel.Data = (ar.AsyncState as SomeWcfService).EndGetInfo(ar);
}
Upvotes: 1