views:

1003

answers:

5

I'm using ADO.NET dataservices in a Silverlight application and since the silverlight libraries don't support the ToList() call on the IQueryable I thought it might be possible to create an extension method around this called SilverlightToList(). So in this method I'm calling the BeginExecute method on my context as shown below:

            var result = context.BeginExecute<T>(currentRequestUri,null,context);
            result.AsyncWaitHandle.WaitOne();
            return context.EndExecute<T>(result).ToList();

The problem is that when I call the WaitOne() method this results in a deadlock. Is this a limitation of ADO.NET dataservices in Silverlight? Is there perhaps a workaround for this?

Thanks in advance!

+1  A: 

Silverlight probably isn't going to like synchronous anything, because it's intended to run in the browser, and it only can have one thread to play with - and it has to share that. And the only thread available for the host is the one provided by the browser.

le dorfier
Isn't only having one thread make it more likely to be able to call items synchronously?
ChrisHDog
No, it means that it needs not to, because it will freeze everything else going on in the browser, across all the tabs.
le dorfier
+1  A: 

I've since found this post on the MSDN forum which says that any managed->UnManaged->Managed marshalling happens on the UI thread which explains why the WaitOne method call is hanging...

James_2195
+1  A: 

All service calls in Silverlight must be asynchronous. So you have to define a callback to get the result - like this:

context.BeginExecute<T>(currentRequestUri, resultCallback, context);

private void resultCallback(IAsyncResult asyncResult)
{
    DataServiceContext context = asyncResult.AsyncState as DataServiceContext;
    var result = context.EndExecute<T>(asyncResult);
    // Do whatever you need with the result here
}

Here's a good reference at MSDN: http://msdn.microsoft.com/en-us/library/cc838191(VS.95).aspx

Boyan
Hi,Thanks for the reponse. I have tried it your way and as you say it does work. The only down side of this method is that I would like to pass the result back to the calling thread. I've seen in the MS documentation that they're generally setting the DataContext of a control to the result.
James_2195
Try using the Dispatcher object of the control to set its DataContext from the result callback method.
Boyan
+1  A: 

Just read today a very good article from Daniel Vaughan (http://danielvaughan.orpius.com/) on synchronous web service calls (http://www.codeproject.com/KB/silverlight/SynchronousSilverlight.aspx). This may help you understand a little bit more on the subject (he uses WCF).

This guy has also built the Clog client-side logging system (http://www.codeproject.com/KB/silverlight/SilverlightLogging.aspx) and a grid computing framework (http://www.codeproject.com/KB/silverlight/gridcomputing.aspx). I am very impressed !!

devMomentum
+1  A: 

I have managed to defeat ( :P ) the async monster in silverlight like so:

var ctx = new ModelEntities(new Uri("http://localhost:2115/Data.svc"));

ManualResetEvent m1 = new ManualResetEvent(false);
ManualResetEvent m2 = new ManualResetEvent(false);

var q1 = (DataServiceQuery<Department>)(from e in ctx.Department select e);
var q2 = (DataServiceQuery<Person>)(from e in ctx.Person select e);

Department[] r1 = null;
Person[] r2 = null;

q1.BeginExecute(r =>
{
    try { r1 = q1.EndExecute(r).ToArray(); }
    finally { m1.Set(); }
}, null);
q2.BeginExecute(r =>
{
    try { r2 = q2.EndExecute(r).ToArray(); }
    finally { m2.Set(); }
}, null);

ThreadPool.QueueUserWorkItem((o) =>
{
    WaitHandle.WaitAll(new WaitHandle[] { m1, m2 });
    // do your thing..
});

The basic ideea is to spawn a waiter thread (the last block) which would have references to the wait objects. DON'T put your WaitAll call in the caller method / thread because this will result in a deadlock as others mentioned earlier on this site or other sites.

The deadlock occurs because the threads are not starting until the method ends and the method does not end because the WaitAll call waits for the child threads to end.

Not in my case above however because the WaitAll is on ANOTHER thread.

PS : Instead of the // do your thing line place code that uses the r1 and r2 captured references which will hold the data or null if that result failed.

Andrei Rinea