Odata on silverlight only works in UI thread

We work with OData in Silverlight, using a DataServiceCollection to retrieve data.

All calls to get data (LoadAsync () LoadNextPartialSetAsync ()) are made in the workflow. However, the "LoadCompleted" callback, as well as object deserialization and materialization, are performed by the user interface thread.

We decompiled System.Data.Services.Client.DLL, where the DataServiceCollection is located, and saw that in fact all the code that processes the OData response is sent to the user interface stream.

Is there a way to get deserialization instead of workflow?

thanks yaron

+4
source share
3 answers

Well...

It seems that OData collections intentionally move UI thread processing. I assume this is done because old objects may have properties to which the interface is bound. These properties may change when additional data is loaded.

Using the request itself, I was able to get a response to the workflow. However, this means that one MUST detach objects from the OData context (or clone them) if the user interface is bound to any property. Otherwise, subsequent requests may result in property changes when objects materialize in the workflow.

+3
source

The problem is that the DataServiceCollection<T> derived from the ObservableCollection<T> . This, in turn, is intended to be bound to user interface elements. When changes in the membership of a ObservableCollection<T> occur, observing a required expression, it is notified. This binding expression then attempts to update the target user interface element. If the notification arrives in a thread other than the UI, then an exception is thrown.

Therefore, DataServiceCollection<T> deliberately transfers materialization to the user interface stream, so that since items are displayed in the collection, received notification of changes do not throw an exception. If this behavior is not acceptable for you, then DataServiceCollection<T> not for you.

Instead, run the query yourself through the DataServiceQuery<T>.BeginExecute . The callback that you pass to BeginExecute will be executed on the BeginExecute (at least when using ClientHTTP, I still set what happens when XmlHttp is used). Here you can list the results and put them in any type of collection you prefer. You can switch to the user interface stream when you are ready to display the results.

+1
source

The callback will always be called in the user interface thread. If the request used the XmlHttp stack (which is the default if you call it from the user interface thread), the network stack calls the callback registered by the WCF data service in the user interface thread. Thus, in this case, this is the behavior of the DataServiceCollection / DataServiceContext, but the behavior of the underlying network stack. If you call a request from a thread other than the UI, or you explicitly set the Http stack by the client, then the callback will return to the thread other than the UI (potentially different). We still transfer it back to the user interface thread before informing the caller. The reason for this is consistency, especially since you cannot interact with user interface elements in the background thread.

If you execute the request manually, for example, through DataServiceContext.BeginExecute, then the materialization (or most of it) will be called by the caller, since the call returns only IEnumerable, which is not yet filled. If you then pass execution to the workflow and list the results there, materialization will occur in that thread.

Just curious why you want to move it? Are you processing so much data that it causes visible user interface lags?

0
source

Source: https://habr.com/ru/post/1369455/


All Articles