I have a Silverlight class library that references a WCF service,
I have a method called StoreNodes() that call the WCF service.
like this:
public void StoreNodes()
{
DataServiceClient client = new DataServiceClient();
client.GetNodesForCoreCompleted += client_GetNodesForCoreCompleted;
client.GetNodesForCoreAsync();
}
and another method called BuildAll() like this:
public void BuildAll()
{
StoreNodes();
Method2();
}
My problem is method2() is not a WCF service, and the both StoreNodes and Method2 have some variables in common, these variables get their values in StoreNodes and the second method do some operation on them, anyway, the problem is the methode2 is executed before the first method finishes, so I got the null reference error. How can I make sure that the second method is executed after the service calling is finished??
I hope I made my question clear.
Something along these lines should work:
public void BuildAll()
{
StoreNodes(() => { Method2(); });
}
public void StoreNodes(Action getNodesCompleteAction)
{
DataServiceClient client = new DataServiceClient();
client.GetNodesForCoreCompleted += (sender, e) => {
// your handler code
// call Method2() Action wrapper
getNodesCompleteAction();
}
client.GetNodesForCoreAsync();
}
There are two ways that you could solve this problem.
First, you can set up a type of async method chaining. After each method completes, it calls the next one:
StoreNodes();
|
V
client_GetNodesForCoreCompleted
|->Method2();
And, you could continue this...
|
V
client_Method2Completed
|->Method3();
....
The other way is that you could put some sort of wait inside of Method2 that will wait until the appropriate variables are set. However, this is against the general programming paradigm of Silverlight, so I would not suggest it realistically. It would lock your UI while you simply wait for a resource. IF, this is what you want, then here is a SO answer on how you could wait for the values
Related
I am looking for a simple way to do a task in background, then update something (on the main thread) when it completes. It's in a low level 'model' class so I can't call InvokeOnMainThread as I don't have an NSObject around. I have this method:
public void GetItemsAsync(Action<Item[]> handleResult)
{
Item[] items=null;
Task task=Task.Factory.StartNew(() =>
{
items=this.CreateItems(); // May take a second or two
});
task.ContinueWith(delegate
{
handleResult(items);
}, TaskScheduler.FromCurrentSynchronizationContext());
}
This seems to work OK, but
1) Is this the best (simplest) way?
2) I'm worried about the local variable:
Item{} items=null
What stops that disappearing when the method returns before the background thread completes?
Thanks.
I think your method slightly violates a Single Responsibility Principle, because it doing too much.
First of all I suggest to change CreateItems to return Task instead of wrapping it in the GetItemsAsync:
public Task<Item[]> CreateItems(CancellationToken token)
{
return Task.Factory.StartNew(() =>
// obtaining the data...
{});
}
CancellationToken is optional but can help you if you able to cancel this long running operation.
With this method you can remove GetItemsAsync entirely because its so simple to handle results by your client without passing this delegate:
// Somewhere in the client of your class
var task = yourClass.CreateItems(token);
task.ContinueWith(t =>
// Code of the delegate that previously
// passed to GetItemsAsync method
{}, TaskScheduler.FromCurrentSynchronizationContext());
Using this approach you'll get more clear code with only one responsibility. Task class itself is a perfect tool for representing asynchronous operation as a first class object. Using proposed technique you can easily mock you current implementation with a fake behavior for unit testing without changing your clients code.
Something like this:
public void GetItemsAsync(Action<Item[]> handleResult)
{
int Id = 11;
Task<Item[]> task = Task.Factory.StartNew(() => CreateItems(Id)); // May take a second or two
task.ContinueWith(t => handleResult(t.Result), TaskScheduler.FromCurrentSynchronizationContext());
}
Your code looks fine.
It's a perfect example of when to use async / await if you can use C# 5, but if not, you have to write it as you have done with continuations.
The items variable is captured in your lambdas, so that's fine too.
When you write a lambda that uses an outside variable, the C# compiler creates a class that contains the variable. This is called a closure and means you can access the variable inside your lambda.
Here is a nicer soultion:
public void GetItemsAsync(Action<Item[]> handleResult)
{
var task = Task.Factory.StartNew<Item[]>(() =>
{
return this.CreateItems(); // May take a second or two
});
task.ContinueWith(delegate
{
handleResult(task.Result);
}, TaskScheduler.FromCurrentSynchronizationContext());
}
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.
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);
}
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:
Your program sets up and begins a service call then keeps doing whatever else it wants, without waiting. Hint: This is a natural place to start a loading animation, and/or disable some controls.
When you made the async call, you gave, as one of your parameters, a method to run once the call is complete.
When the service returns with results, the method you specified is run to do work on the results. Hint: In this method, you can end the loading animation, and/or re-enable your controls, and plug the results into your ViewModel.
I have a method like this:
public IOrganizationService GetConnection(bool multi)
{
if(!multi)
{
Parallel.For(0, 1, i =>
{
dynamic _serviceobject= InitializeCRMService();
});
}
else
{
ThreadPool.QueueUserWorkItem
(
new WaitCallback
(
(_) =>
{
dynamic _serviceobject= InitializeCRMService();
}
)
);
}
}
I want to return the _serviceobject *directly* from inside the method.Will returing it twice i.e once from if and once from the else loop solve my problem.Please note I am using Multithreading using the concept of Pool threading.Will the _serviceobjects stay unique in case two threads are running parallely.I do not wan't any interaction to happen between my threads.
The code inside of WaitCallback will execute in the thread pool, and will do so probably after GetConnection has returned (that's the point of doing asynchronous operations). So, since it is another thread (with another call stack) and it will potentially execute after GetConnection has returned, you cannot make GetConnection return from inside of WaitCallback. If you really want to do that, then you will have to make GetConnection wait until WaitCallback has completed execution. ManualResetEvent can do the trick:
public IOrganizationService GetConnection(bool multi)
{
var waitHandle = new ManualResetEvent(false);
dynamic result = null;
if(!multi)
{
Parallel.For(0, 1, i =>
{
result = InitializeCRMService();
waitHandle.Set();
});
}
else
{
ThreadPool.QueueUserWorkItem
(
new WaitCallback
(
(_) =>
{
result = InitializeCRMService();
waitHandle.Set();
}
)
);
}
//We wait until the job is done...
waitHandle.WaitOne();
return result as IOrganizationService; //Or use an adecuate casting
}
But doing this defies the point of having asynchronous operations in the first place. Since the caller thread will have to wait until the job is done in another thread, sitting there, doing nothing... Then, why don't just do it synchrnously? In a word: Pointless.
The problems is that returning the value directly is a synchronous API. If you want asyncrhonous operations, you will want an asycrhonous API. If you will have an asynchronous API then you are going to have to change the way the caller works.
Solutions include:
Having a public property to access the reuslt (option 1)
Having a callback (option 2)
resourcing to events
Returning a Task (or use the async keywork if available)
Returning IObservable (using Reactive Extensions if available)
Notes:
Having a puplic property means you will need to deal with syncrhonization in the caller.
Having a callback, means an odd way to call the method and no explicit way to wait.
Using events has the risk of the caller staying subscribed to the event handler.
Returning a Task seems like an overkill since you are using the thread pool.
Using IObservable without Reactive Extension is prone to error, and much more work compared to the alternatives.
Personally I would go for the callback option:
public void GetConnection(bool multi, Action<IOrganizationService> callback)
{
if (ReferenceEquals(callback, null))
{
throw new ArgumentNullException("callback");
}
if(!multi)
{
Parallel.For(0, 1, i =>
{
callback(InitializeCRMService() as IOrganizationService);
//Or instead of using "as", use an adecuate casting
});
}
else
{
ThreadPool.QueueUserWorkItem
(
new WaitCallback
(
(_) =>
{
callback(InitializeCRMService() as IOrganizationService);
//Or instead of using "as", use an adecuate casting
}
)
);
}
}
The caller then does something like this:
GetConnection
(
false,
(seriveObject) =>
{
/* do something with seriveObject here */
}
);
//Remember, even after GetConnection completed seriveObject may not be ready
// That's because it is asyncrhonous: you want to say "hey Bob do this for me"
// and you can go do something else
// after a while Bob comes back an says:
// "that thing you asked me to do? well here is the result".
// We call that a callback, and the point is that you didn't have to wait for Bob
// you just kept doing your stuff...
//So... when is seriveObject ready? I don't know.
//But when seriveObject is ready the callback will run and then you can use it
You cannot return it from inside the WaitCallback handler because there's no one in your code to return it to. That's just a callback.
You may want to try defining a custom event (derived from EventArgs) which has a dynamic member.
Then you can raise this event from your worker entry point and also send with it the dynamic object.
You can bind to the event where needed (i.e. where you want to use the dynamic object).
EDIT (to also show some code):
In the same class where you have your GetConnection method, also define an event:
internal event EventHandler<SomeEventArgs> OnWorkerFinished = (s, e) => {};
then, define somewhere in your project (close to this class), the SomeEventArgs class:
internal class SomeEventArgs : EventArgs
{
public dynamic WorkerResult { get; private set; }
public SomeEventArgs(dynamic workerResult)
{
WorkerResult = workerResult;
}
}
Next, in the worker:
new WaitCallback
(
(_) =>
{
dynamic _serviceobject= InitializeCRMService();
//Here raise the event
SomeEventArgs e = new SomeEventArgs(_serviceObject);
OnWorkerFinished(this, e);
}
)
I don't know where you want to use get the result, but in that place you should bind to the OnWorkerFinished event of this class (in which you have the GetConnectionMethod).
In my application, I used to create along string of async operations, which passed in functions like this:
public void LotsOfAsync()
{
DoAsync1( ()=> { DoAsync2( ()=> { doAsync3( ()=> { finalAction();}) } ) } );
}
However, now I have moved many of those async operations into separate classes and objects but I want the same results. Mainly I have moved those async operations into classes which become part of a collection.
I'd like my new code to look like this:
public void lotsOfAsync()
{
DoAsync1();
for each ( MyClass in Async1List)
{
MyClass.DoAsyn2();
}
if (allAsyncOperationsAreComplete)
{
FinalAction();
}
}
What things do I need to do, to get this to work? Thanks.
Using the Answer below about Tasks, something still seems to be lacking. The program never continues even after throwing everything into a BackgroundWorker.
You can use Task<T> (using the Task Parallel Library for Silverlight) - something like this maybe:
List<Task> tasks = new List<Task>();
Task.Factory.StartNew(() => DoAsync1()).ContinueWith(_ =>
{
foreach (MyClass myClass in Async1List)
{
tasks.Add(Task.Factory.StartNew(() => myClass.DoSomething()));
}
Task.WaitAll(tasks.ToArray());
FinalAction();
});
Im not familiar with wp7, but you may use counter as static field and check if it's equal to 0 in final action.
Every MyClass.DoAsyn2() should fire maybe a event, or any other code to signal that it is finished.
Another option is to move all async to task and call Task.WaitAll
http://msdn.microsoft.com/en-us/library/dd270695.aspx
Have you had a look at the CountdownEvent in .Net 4? This is a signalling construct where one thread will block and only proceed once other threads have completed and called set on the count down event. You initialise it with the number of signals you need before the thread calling Wait on the construct will proceed. E.g.:
CountdownEvent countdown = new CountdownEvent(3);
will only let the thread calling Wait to proceed once 3 other threads have called Signal.
So your example would perhaps look something like this:
public void lotsOfAsync()
{
Int32 numberOfAsyncProcesses = Async1List.Length + 1;
CountdownEvent countdown = new CountdownEvent (numberOfAsyncProcesses);
DoAsync1(countdown); // call countdown.signal() in the async method once complete.
for each ( MyClass in Async1List)
{
// call countdown.signal() in the async method once complete.
MyClass.DoAsyn2(countdown);
}
if(countDown.Wait(TimeSpan.FromSeconds(3))
{
FinalAction();
}
}
I've also added a timeout where the calling thread will unblock after 3 seconds if failed to get a response from all processing threads. In this case, the final action will not be performed.
You can reproduce this with Monitor/Pulse if you are not targeting .Net 4.
There is a nice example here too. Hope this helps!
After looking through all the previous answers, I was unable to solve my problem.
Instead what I needed to do, was create custom Events within my classes, which triggered upon a successful completion of the asynchronous tasks.
The website that proved the most useful to me to accomplish this was: http://www.marten-online.com/csharp/simple-custom-event-handling.html
My final code looked something like this:
public void lotsOfAsync()
{
DoAsync1();
for each ( MyClass in Async1List)
{
MyClass.PropertyChange += new MyClass.PropertyChangeHandler(Async2Complete);
MyClass.DoAsyn2();
}
}
public void Async2Complete(object sender, PropertyChangeEventArgs data)
{
if (data.PropertyName == "AsyncComplete")
{
totalAsyncCompleted++;
if (totalAsyncCompleted >= Async1List.Count)
{
FinalAction();
}
}
}
Have you heard of the Deferred pattern often used in Javascript?
It is simple to work with and very dynamic and you should be able to implement it on Windows phone aswell.
Have a look at this guide
http://twistedmatrix.com/documents/current/core/howto/defer.html
Regards
Tobias
I'm at my wits end trying to solve this issue.
I have a function in a class as such
public class ReceiveData
{
Dataprovider provider = new DataProvider();
public void ResponseData()
{
foreach(string anItem in TheList)
{
// AllData function is declared in class DataProvider
string result = provider.AllData(anItem);
}
//do something
}
}
That's simple. However, what would I do if AllData function had to make async function calls to get data?
Meaning, say
public class DataProvider
{
MyServiceClient client = new MyServiceClient();
public string AllData (string myItem)
{
client.FormattedDataCompleted += new EventHandler<FormattedDataCompletedEventArgs>(client_FormattedDataCompleted);
client.FormattedDataAsync(myItem);
}
void client_FormattedDataCompleted(object sender, FormattedDataCompletedEventArgs e)
{
// here's where the response comes back.
}
As you can see, now I cant simply call AllData function and directly get data back.
So, what would I have to do in ResponseData function to make sure I call the AllItem function, and get data back from the callback. Notice that there's a loop in that function, so I need to all the parameters I have sent through the loop gets respective response.
One approach I tried was by using AutoResetEvent class.
I defined a handler for this as
AutoResetEvent handle = new AutoResetHandle(false);
then I add handle.WaitOne() right after the async call. and on the callback, added handle.Set();
However, the applications get stuck at handle.WaitOne(). So I can't really see why that happens.
I now have a theoritical idea to see if I could have a event raiser on the callback, and an eventlistener in RecieveData class, and if those two communicate, I could get the data. But I've spent some time trying to learn more about event handlers, but haven't gotten the hang of it.
So does anybody have any other approach, ideas? Thanks!
Welcome to the asynchronous model. You have to re-think how you call methods when you go multithreaded.
You have some options:
Split the method in which you're making the call into two halves; in the first half, call AllData, do ANYTHING else you can possibly do without having the response object, and then exit your current method. When the async call completes, it'll call your handler, where you should perform all operations from the original method that require the response.
In the event handler for the async call completion, set a property that indicates the call is completed, and put the data out on a property somewhere as well. In the function that kicks off the call, at the point where you simply cannot continue execution until the call completes, wait in a while loop for the call to complete by polling the property and breaking once it indicates the call has been completed (you'll probably want a Thread.Yield() in the loop as well that you'll call when you haven't gotten a response yet, to make sure you aren't blocking other threads doing more important things than waiting)
Wrap your asynchronous call in a class that exposes a synchronous method. The wrapper class will have similar logic as integrating the async call into your method. It will make the call, wait for the response, and return that response as if it were a normal synchronous method call.
Remember that the asynchronous call is giving your calling thread the opportunity to do other work while the call is performed. Take full advantage of this if at all possible.
You just need to use a delegate and call BeginInvoke. You can then set a callback method to capture the result of the delegate call.
public class ReceiveData
{
private List<string> TheList = new List<string>
{
"1", "2", "3"
};
dynamic provider = new ExpandoObject();
public void ResponseData()
{
foreach (string anItem in TheList)
{
// AllData function is declared in class DataProvider
Func<string, string> asyncAllData = provider.AllData;
asyncAllData.BeginInvoke(anItem, AllDataDone, null);
}
//do something
}
private void AllDataDone(IAsyncResult iar)
{
AsyncResult ar = (AsyncResult)iar;
var del = (Func<string, string>)ar.AsyncDelegate;
// here's your result
string result = del.EndInvoke(iar);
}
}