So I'm reading up on Rx and having a difficult time grokking it. I have a Silverlight app that needs to make say 6 calls to a specific service asynchronously. In the old days, we'd handle this by making the calls and querying the userState/token to match the response with the request since they're not guaranteed to return in the order we called them. However, I suspect Rx handles this in a far more elegant manner. But I can't get it to work. Here's what I have so far...
myCollection.Add(new myObject(1));
myCollection.Add(new myObject(2));
myCollection.Add(new myObject(3));
myCollection.Add(new myObject(4));
myCollection.Add(new myObject(5));
myCollection.Add(new myObject(6));
foreach (var myItem in myCollection)
{
var myObservable = Observable.FromEventPattern<MyServiceMethodCompletedEventArgs>
(
f => myServiceClient.MyServiceMethodCompleted += f,
f => myServiceClient.MyServiceMethodCompleted -= f
).Take(1).ObserveOn(SynchronizationContext.Current);
myObservable.Subscribe
(
s =>
{
if (s.EventArgs.Error == null)
{
myItem.MyProperty = s.EventArgs.Result;
}
}
);
myServiceClient.MyServiceMethodAsync(myItem);
}
I hope you can see what I'm trying to achieve here...
What I end up with is all of myObject's being set to the result of the first call that returns.
I'm sure it's something silly but I haven't been able to figure it out yet.
Thanks :)
Consider trying the Observable.FromAsyncPattern instead of Observable.FromEventPattern. There is a trick to using FromAsyncPattern in Silverlight (and the phone) because the BeginInvoke/EndInvoke pair are not exposed directly by the service proxy. However, if you use the interface for the service proxy rather than the service proxy itself, you can access the begin/end pattern:
IMyService svc = new myServiceClient();
var svcObservable = Observable.FromAsyncPattern<T, MyServiceResultArgs>
(svc.BeginMyServiceMethod, svc.EndMyServiceMethod);
Now, you can switch from using foreach (an anti-pattern with LINQ) to making your myCollection into an observable and SelectMany between the myCollection and the service request as follows:
var requestResult = from myItem in myCollection.ToObservable()
from result in svcObservable(myItem)
select new {myItem, result};
requestResult.Subscribe(result => result.myItem.myProperty = result.result);
One additional word of caution: If you use the FromAsyncPattern in silverlight this way, the result will come back on a background thread. You will need to take care teo delegate back to the dispatcher.
If you want to see this in action, check out the last 20 minutes or so of my Mix presentation at http://channel9.msdn.com/events/MIX/MIX11/EXT08.
Related
I fetch data for a wpf window in a backgroundthread like this [framework 4.0 with async/await]:
async void refresh()
{
// returns object of type Instances
DataContext = await Task.Factory.StartNew(() => serviceagent.GetInstances());
var instances = DataContext as Instances;
await Task.Factory.StartNew(() => serviceagent.GetGroups(instances));
// * problem here * instances.Groups is filled but UI not updated
}
When I include the actions of GetGroups in GetInstances the UI shows the groups.
When I update in a seperate action the DataContext includes the groups correclty but the UI doesn't show them.
In the GetGroups() method I inlcuded NotifyCollectionChangedAction.Reset for the ObservableCollection of groups and this doesn't help.
Extra strange is that I call NotifyCollectionChangedAction.Reset on the list only once, but is executed three times, while the list has ten items?!
I can solve the issue by writing:
DataContext = await Task.Factory.StartNew(() => serviceagent.GetGroups(instances));
But is this the regular way for updating DataContxt and UI via a backgound process?
Actually I only want to update the existing DataContext without setting it again?
EDIT: serviceagent.GetGroups(instances) in more detail:
public void GetGroups(Instances instances)
{
// web call
instances.Admin = service.GetAdmin();
// set groups for binding in UI
instances.Groups = new ViewModelCollection<Groep>(instances.Admin.Groups);
// this code has no effect
instances.Groups.RaiseCollectionChanged();
}
Here ViewModelCollection<T> inherits from ObservableCollection<T> and I added the method:
public void RaiseCollectionChanged()
{
var handler = CollectionChanged;
if (handler != null)
{
Trace.WriteLine("collection changed");
var e = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
handler(this, e);
}
}
There's a few points that stand out in the async portion of your code:
I explain why we should avoid async void in my MSDN article. In summary, void is an unnatural return type for async methods, so it has some quirks, particularly around exception handling.
We should prefer TaskEx.Run over StartNew for asynchronous tasks, as I explain on my blog.
While not exactly required, it's a good idea to follow the guidelines in the Task-based Asynchronous Pattern; following those naming conventions (etc) will help other developers to maintain the code.
Based on these, I also recommend my intro to async blog post.
On to the actual problem...
Updating data-bound code from background threads is always tricky. I recommend that you treat your ViewModel data as though it were part of the UI (it is a "logical UI", so to speak). So it's fine to retrieve data on a background thread, but updating the actual VM values should be done on the UI thread.
These changes make your code look more like this:
async Task RefreshAsync()
{
var instances = await TaskEx.Run(() => serviceagent.GetInstances());
DataContext = instances;
var groupResults = await TaskEx.Run(() => serviceagent.GetGroups(instances));
instances.Admin = groupResults.Admin;
instances.Groups = new ObservableCollection<Group>(groupResults.Groups);
}
public GroupsResult GetGroups(Instances instances)
{
return new GroupsResult
{
Admin = service.GetAdmin(),
Groups = Admin.Groups.ToArray(),
};
}
The next thing you need to check is whether Instances implements INotifyPropertyChanged. You don't need to raise a Reset collection changed event when setting Groups; since Groups is a property on Instances, it's the responsibility of Instances to raise INotifyPropertyChanged.PropertyChanged.
Alternatively, you could just set DataContext last:
async Task RefreshAsync()
{
var instances = await TaskEx.Run(() => serviceagent.GetInstances());
var groupResults = await TaskEx.Run(() => serviceagent.GetGroups(instances));
instances.Admin = groupResults.Admin;
instances.Groups = new ObservableCollection<Group>(groupResults.Admin.Groups);
DataContext = instances;
}
Seems there's a bit of confusion on what DataContext is. DataContext is not some special object that you have to update. It's a reference to the object or objects that you want to bind to your UI. Whenever you make changest to these objects, the UI get's notified (if you implement the proper interfaces).
So, unless you explicitly change the DataContext, your UI can't guess that now you want to show a different set of objects.
In fact, in your code, there is no reason to set the DataContext twice. Just set it with the final set of objects you want to display. In fact, since you work on the same data, there is no reason to use two tasks:
async Task refresh()
{
// returns object of type Instances
DataContext=await Task.Factory.StartNew(() => {
var instances = serviceagent.GetInstances();
return serviceagent.GetGroups(instances);
});
}
NOTE:
You should neer use the async void signature. It is used only for fire-and-forget event handlers, where you don't care whether they succeed or fail. The reason is that an async void method can't be awaited so no-one can know whether it succeeded or not.
I discovered that RaiseCollectionChanged has no influence on the property Groups where the DataContext is bound to. I simply have to notify: instances.RaisePropertyChanged("Groups");.
See bottom of post for my pseudo solution.
Once again I'm completely and utterly stuck on this. I've burned hours trying to understand - and yes I can get a single collectionviewsource to work beautifully with nothing about threading on the code behind.
Imagine my shock when I found merely adding two collectionviewsources on the page causes threading issues. I've spent a few hours last night reading Async in C#5 and the MSDN stuff however I get into work today and I can't decipher how to make this happen.
The code below is the last attempt I've made before whining for help as I've burnt, possibly, a bit too much work time on attempting to understand how to do this. I understand that I need one collectionviewsource to complete before starting the other, so I tried Await Task.ContinueWith etc to try and chain one after the other.
Lining up both sets of tasks in the threads correctly seems to be quite tricky, or I'm still misunderstanding something fundemental.
If anyone can advise how they would asynchronously populate a few controls on a WPF UI I would be very grateful.
The application itself is a throwaway application, linked to an Access database that I'm using to try and become fluent enough in threading to implement it in our proper code base. I'm long way off that!
Updated with more complete code samples and the adjustments made according to answers:
Private Async Sub MainWindowLoaded(sender As Object, e As RoutedEventArgs) Handles MyBase.Loaded
InitializeComponent()
Dim personSetViewSource As System.Windows.Data.CollectionViewSource = CType(Me.FindResource("personSetViewSource"), System.Windows.Data.CollectionViewSource)
Dim contactSetViewSource As System.Windows.Data.CollectionViewSource = CType(Me.FindResource("contactSetViewSource"), System.Windows.Data.CollectionViewSource)
Dim personList = Await Task.Run(Function() personSet.personList)
personSetViewSource.Source = personList
Dim contactList = Await Task.Run(Function() contactSet.contactList)
contactSetViewSource.Source = contactList
End Sub`
The ObservableCollectionEx class:
public class ObservableCollectionEx<T> : ObservableCollection<T>
{
public override event NotifyCollectionChangedEventHandler CollectionChanged;
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
using (BlockReentrancy())
{
NotifyCollectionChangedEventHandler collectionChanged = this.CollectionChanged;
if (collectionChanged != null)
foreach (NotifyCollectionChangedEventHandler nh in collectionChanged.GetInvocationList())
{
DispatcherObject dispObj = nh.Target as DispatcherObject;
if (dispObj != null)
{
Dispatcher dispatcher = dispObj.Dispatcher;
if (dispatcher != null && !dispatcher.CheckAccess())
{
NotifyCollectionChangedEventHandler nh1 = nh;
dispatcher.BeginInvoke(
(Action) (() => nh1.Invoke(this,
new NotifyCollectionChangedEventArgs(
NotifyCollectionChangedAction.Reset))),
DispatcherPriority.DataBind);
continue;
}
}
nh.Invoke(this, e);
}
}
}
}
Please note, I can't translate this class to VB due to requiring an Event Override.
Another variation I've tried, but falls foul of thread ownership again. The two collectionviews thing isn't yielding to a solution: I don't know if it's because the underlying collection isn't good for it or whether in reality it wasn't meant to work that way. I get close but no cigar.
Dim CarePlanList = Task.Run(Function() CarePlanSet.CarePlanList)
Dim rcpdList = Task.Run(Function() rcpdSet.rcpdList)
Dim tasks() As Task = {CarePlanList, rcpdList}
Dim t = New TaskFactory
Await t.ContinueWhenAll(tasks, Sub()
carePlanSetViewSource.Source = CarePlanList
rcpdSetViewSource.Source = rcpdList
End Sub)
I found a way to do it, based on a combination of feedback and research this morning. Building the two collectionviews asynchronously itself is somewhat impractical given the STAThread model of WPF. However, merely ensuring one HAS completed and shifting some of the async out of one entity class has made this plausible.
Instead I fire off the first task, who's underlying class does build it's data with its own Async method. Then test to see if it has completed before allowing the second collectionview to be fired off. This way I don't need to worry about context or dispatcherobjects. The second collection does not use any async.
Dim personList = Task(Of List(Of person)).Run(Function() personSet.personList)
Dim contactList = Task(Of ObservableCollectionEx(Of contact)).Run(Function() contactSet.contactList)
contactSetViewSource.Source = contactList.Result
If contactList.IsCompleted Then personSetViewSource.Source = personList.Result
This is an experimental project for concept research really. As it happens, the idea I'd want two such lists built this way isn't as useful as all that but I do see where being able to compose a data heavy interface asynchronously could be handy.
Your two code samples each have issues that jump out right away.
In the first you are awaiting task1, I assume with more code following, but all task1 is doing is starting what is basically a fire and forget operation back to the UI thread (Dispatcher.BeginInvoke), therefore not really producing anything asynchronous to await.
In the second, the primary issue seems to be that you are doing a lot of setup of Task instances and chaining them with continuations but never starting the action2 Task, which appears to be the root of the whole chain, hence getting no activity at all. This is similar to what you get with a BackgroundWorker that never has RunWorkerAsync called.
To get this working properly and avoid making your head spin any more I would suggest starting by writing this whole block without any async and verifying that everything loads as expected, but with the UI lockup you want to avoid. Async/Await is designed to be added into code like that with minimal structural changes. Using Task.Run along with async and await you can then make the code asynchronous.
Here's some pseudocode for the basic pattern, without async to start:
PersonSetList = LoadData1()
CVS1.Source = PersonSetList
ContactList = LoadData2()
CVS2.Source = ContactList
and now adding async:
PersonSetList = await Task.Run(LoadData1())
CVS1.Source = PersonSetList
ContactList = await Task.Run(LoadData2())
CVS2.Source = ContactList
What this will now do is start a task to load the person data and immediately return from your WindowLoaded method, allow the UI to continue rendering. When that data is loaded it will continue to the next line on the original thread and push the data into the UI (which may itself slow down the UI while rendering). After that it will do the same for the Contact data. Notice that Dispatcher isn't needed explicitly because await is returning back to the UI thread for you to complete its continuation.
I'm building a Silverlight Web Resource which is intended to integrate into a form, and it needs to know all of the following information:
id of the current user
id of teams current user belongs to
id of current user's security roles
I'm working in an early-bound kind of way, added a Service Reference to the OData endpoint (http://server/org/XRMservices/2011/OrganizationData.svc) which in turn provides me with the context (let's name it cmtestcontext, which is its actual name in code).
I access data through this class (I didn't create it, I just googled it out of the net some time ago: this is a stripped-down, keep-it-short version)
public class QueryInterface
{
//NOTE: ServiceReference1 is the name of the OData service reference
//Add Service Reference -> point to CRM OData url
public ServiceReference1.cmtextcontext CrmContext;
public QueryInterface()
{
var crmServerUrl = (string)GetContext().Invoke("getServerUrl");
if (crmServerUrl.EndsWith("/")) crmServerUrl = crmServerUrl.Substring(0, crmServerUrl.Length - 1);
Uri ODataUri = new Uri(crmServerUrl + "/xrmservices/2011/organizationdata.svc/", UriKind.Absolute);
CrmContext = new cmtestContext(ODataUri) { IgnoreMissingProperties = true };
}
}
The class allows me to sort of fetch in one line, as follows (actual code snippet enveloped in a dummy method to make it copy-pastable):
void RetrieveAllInformationFromCRM()
{
QueryInterface qi = new QueryInterface();
List<Guid> allData = new List<Guid>();
//NOTE: STEP 1 - USER ID
//NOTE: Since this is a web resource, I can cheat and use Xrm.Page.context.getUserId()
//NOTE: Remove the extra '{}' from the result for it to be parsed!
allData.Add(new Guid(qi.GetContext().Invoke("getUserId").ToString().Substring(1,36)));
//NOTE: STEP 2a - TEAM MEMBERSHIP FOR USER
//NOTE: TeamMembership entity links users to teams in a N:N relationship
qi.crmContext.TeamMembershipSet.BeginExecute(new AsyncCallback((result) =>
{
var teamMemberships = qi.crmContext.TeamMembershipSet.EndExecute(result)
.Where(tm => tm.TeamId.HasValue && (tm.SystemUserId ?? Guid.Empty) == userId)
.Select(tm => tm.TeamId.Value);
//NOTE: STEP 2b - TEAMS RELATED TO TEAMMEMBERSHIPS
qi.crmContext.TeamSet.BeginExecute(new AsyncCallback((result2) =>
{
var teamDetails = qi.crmContext.TeamSet.EndExecute(result2)
.Where(t => teamMemberships.Contains(t.TeamId));
foreach (var team in teamDetails)
allData.Add(team.TeamId);
//NOTE: FINAL STEP - allData is filled and ready to be used.
}), null);
}), null);
}
In the code above, my FINAL STEP picks up allData and processes it, and the flow goes on. My concern is, if/when I'll need to modify this "reader" method I'll have to cut and paste the "final" code around to ensure it's placed after all the reads. I'd like it way better if I could just make the reads follow one another, so I could do this:
void MyReaderMethod()
{
ReadEverything();
ProcessData();
}
Basically, can you just wait for a request to finish ? Hanging UI is a non-issue, I'd just wrap the code in a BackgroundWorker along with a "Please Wait" splash.
The nicest (IMO) is to convert the Async method calls (a requirement of Silverlight) into Task based calls.
With tasks you can easily seperate the query from the result action.
Then using the Async BCL's (via nuget) you can use async/await (if you are not using VS2012, then Tasks are still nicer to work with, you will just have to use continuations)
This example is for late bound, but you can modify it for your needs
public Task<OrganizationResponse> ExecuteAsync(OrganizationRequest request)
{
return Task.Factory.FromAsync<OrganizationResponse>(
(callback, state) => Begin(() => service.BeginExecute(request, callback, state)),
service.EndExecute,
null);
}
Then you can use it like
async void MyReaderMethod()
{
//TODO:wrap in try/catch
var result = await ExecuteAsync( ... );
ProcessData(result);
}
Or for VS 2010
void MyReaderMethod()
{
ExecuteAsync( ... ).ContinueWith(task =>{
//TODO: Error handling
ProcessData(task.Result);
});
}
My questions are many. Since I saw. NET 4.5, I was very impressed. Unfortunately all my projects are .NET 4.0 and I am not thinking about migrating. So I would like to simplify my code.
Currently, most of my code that usually take enough time to freeze the screen, I do the following:
BackgroundWorker bd = new BackgroundWorker();
bd.DoWork += (a, r) =>
{
r.Result = ProcessMethod(r.Argument);
};
bd.RunWorkerCompleted += (a, r) =>
{
UpdateView(r.Result);
};
bd.RunWorkerAsync(args);
Honestly, I'm tired of it. And that becomes a big problem when there is a logic complex user interaction.
I wonder, how to simplify this logic? (Remember that I'm with. Net 4.0) I noticed a few things by google, but not found anything easy to implement and suitable for my needs.
I thought this solution below:
var foo = args as Foo;
var result = AsyncHelper.CustomInvoke<Foo>(ProcessMethod, foo);
UpdateView(result);
public static class AsyncHelper
{
public static T CustomInvoke<T>(Func<T, T> func, T param) where T : class
{
T result = null;
DispatcherFrame frame = new DispatcherFrame();
Task.Factory.StartNew(() =>
{
result = func(param);
frame.Continue = false;
});
Dispatcher.PushFrame(frame);
return result;
}
}
I am not sure about the impact is on manipulating the dispatcher frame.
But I know That it would work very well, for example, I could use it in all the events of controls without bothering to freeze the screen.
My knowledge about generic types, covariance, contravariance is limited, maybe this code can be improved.
I thought of other things using Task.Factory.StartNew and Dispatcher.Invoke, but nothing that seems interesting and simple to use. Can anyone give me some light?
You should just use the Task Parallel Library (TPL). The key is specifying the TaskScheduler for the current SynchronizationContext for any continuations in which you update the UI. For example:
Task.Factory.StartNew(() =>
{
return ProcessMethod(yourArgument);
})
.ContinueWith(antecedent =>
{
UpdateView(antecedent.Result);
},
TaskScheduler.FromCurrentSynchronizationContext());
Aside from some exception handling when accessing the antecedent's Result property, that's all there is too it. By using FromCurrentSynchronizationContext() the ambient SynchronizationContext that comes from WPF (i.e. the DispatcherSynchronizationContext) will be used to execute the continuation. This is the same as calling Dispatcher.[Begin]Invoke, but you are completely abstracted from it.
If you wanted to get even "cleaner", if you control ProcessMethod I would actually rewrite that to return a Task and let it own how that gets spun up (can still use StartNew internally). That way you abstract the caller from the async execution decisions that ProcessMethod might want to make on its own and instead they only have to worry about chaining on a continuation to wait for the result.
UPDATE 5/22/2013
It should be noted that with the advent of .NET 4.5 and the async language support in C# this prescribed technique is outdated and you can simply rely on those features to execute a specific task using await Task.Run and then execution after that will take place on the Dispatcher thread again automagically. So something like this:
MyResultType processingResult = await Task.Run(() =>
{
return ProcessMethod(yourArgument);
});
UpdateView(processingResult);
How about encapsulating the code that is always the same in a reusable component? You could create a Freezable which implements ICommand, exposes a property of Type DoWorkEventHandler and a Result property. On ICommand.Executed, it would create a BackgroundWorker and wire up the delegates for DoWork and Completed, using the value of the DoWorkEventHandler as event handler, and handling Completed in a way that it sets its own Result property to the result returned in the event.
You'd configure the component in XAML, using a converter to bind the DoWorkEventHandler property to a method on the ViewModel (I assume you've got one), and bind your View to the component's Result property, so it gets updated automatically when Result does a change notification.
The advantages of this solution are: it is reusable, and it works with XAML only, so no more glue code in your ViewModel just for handling BackgroundWorkers. If you don't need your background process to report progress, it could even be unaware that it runs on a background thread, so you can decide in the XAML whether you want to call a method synchronously or asynchronously.
A few months have passed, but could this help you?
Using async/await without .NET Framework 4.5
I'm in the middle of a Silverlight application and I have a function which needs to call a webservice and using the result complete the rest of the function.
My issue is that I would have normally done a synchronous web service call got the result and using that carried on with the function. As Silverlight doesn't support synchronous web service calls without additional custom classes to mimic it, I figure it would be best to go with the flow of async rather than fight it. So my question relates around whats the best design pattern for working with async calls in program flow.
In the following example I want to use the myFunction TypeId parameter depending on the return value of the web service call. But I don't want to call the web service until this function is called. How can I alter my code design to allow for the async call?
string _myPath;
bool myFunction(Guid TypeId)
{
WS_WebService1.WS_WebService1SoapClient proxy = new WS_WebService1.WS_WebService1SoapClient();
proxy.GetPathByTypeIdCompleted += new System.EventHandler<WS_WebService1.GetPathByTypeIdCompleted>(proxy_GetPathByTypeIdCompleted);
proxy.GetPathByTypeIdAsync(TypeId);
// Get return value
if (myPath == "\\Server1")
{
//Use the TypeId parameter in here
}
}
void proxy_GetPathByTypeIdCompleted(object sender, WS_WebService1.GetPathByTypeIdCompletedEventArgs e)
{
string server = e.Result.Server;
myPath = '\\' + server;
}
Thanks in advance,
Mike
The best would be to use Reactive Extensions. Then (assuming you'd create an extension method IObservable<string> GetPathByTypeId(string typeId) on WS_WebService1SoapClient you can do this:
proxy
.GetPathByTypeId(TypeId)
.Subscribe(server =>
{
//Here you can do stuff with the returned value
});
As close to having synchronous call as it gets :)
Given the asynch nature of Silverlight you cannot return values from myFunction. Instead you can pass an Action which is executed once the service call is complete. See the example code below. I am not sure if it is considered best practice, but I use this "pattern" a lot and it has always worked fine for me.
EDIT
Updated the code below to include multiple arguments in the callback action.
void DoSomething(Guid TypeId, Action<int, bool> Callback)
{
WS_WebService1.WS_WebService1SoapClient proxy = new WS_WebService1.WS_WebService1SoapClient();
proxy.GetPathByTypeIdCompleted += (s, e) =>
{
string server = e.Result.Server;
myPath = '\\' + server;
//
if (myPath == "\\Server1")
{
Callback(888, true);
}
else
{
Callback(999, false);
}
};
proxy.GetPathByTypeIdAsync(TypeId);
}
void CallDoSomething()
{
DoSomething(Guid.NewGuid(), (returnValue1, returnValue2) =>
{
//Here you can do stuff with the returned value(s)
});
}
Put the processing of the GetPathByTypeId result into the GetPathByTypeIdCompleted callback. Assign mypath there. Make mypath a property and implement the INotifyPropertyChanged interface to notify dependents of Mypath that Mypath has changed.
Observer depends on mypath
Observer sets a notification event for mypath
Get Mypath by asynchronous invocation of GetPathByTypeId
Mypath is set, invokes notifiaction of Observer
Observer works with Mypath