【问题标题】:Synchronous ADO.NET dataservices calls in SilverlightSilverlight 中的同步 ADO.NET 数据服务调用
【发布时间】:2008-12-09 02:50:49
【问题描述】:

我在 Silverlight 应用程序中使用 ADO.NET 数据服务,由于 silverlight 库不支持对 IQueryable 的 ToList() 调用,我认为可以围绕此创建一个名为 SilverlightToList() 的扩展方法。所以在这个方法中,我在我的上下文中调用 BeginExecute 方法,如下所示:

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

问题是当我调用 WaitOne() 方法时,这会导致死锁。这是 Silverlight 中 ADO.NET 数据服务的限制吗?是否有解决方法?

【问题讨论】:

  • 好问题,Silverlight 中的常见问题

标签: silverlight wcf-data-services


【解决方案1】:

我已经成功击败( :P )silverlight 中的异步怪物,如下所示:

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..
});

基本的想法是产生一个等待对象的引用的等待线程(最后一个块)。不要将您的 WaitAll 调用放在调用方方法/线程中,因为这会导致死锁,正如本网站或其他网站之前提到的那样。

发生死锁是因为线程直到方法结束才开始,并且方法没有结束,因为 WaitAll 调用等待子线程结束。

在我上面的例子中不是,因为 WaitAll 在另一个线程上。

PS : 而不是 // do your thing 行放置代码,它使用 r1 和 r2 捕获的引用,如果结果失败,它将保存数据或 null。

【讨论】:

    【解决方案2】:

    我后来在 MSDN 论坛上找到了 this post,它说任何托管->非托管->托管编组都发生在 UI 线程上,这解释了为什么 WaitOne 方法调用挂起...

    【讨论】:

      【解决方案3】:

      Silverlight 可能不喜欢同步任何东西,因为它旨在在浏览器中运行,而且它只能使用一个线程——而且它必须共享它。而主机唯一可用的线程是浏览器提供的线程。

      【讨论】:

      • 只有一个线程不是更有可能同步调用项目吗?
      • 不,这意味着它不需要这样做,因为它会冻结浏览器中所有选项卡中发生的所有其他事情。
      【解决方案4】:

      Silverlight 中的所有服务调用都必须是异步的。所以你必须定义一个回调来得到结果——像这样:

      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
      }
      

      这是 MSDN 上的一个很好的参考:http://msdn.microsoft.com/en-us/library/cc838191(VS.95).aspx

      【讨论】:

      • 您好,感谢您的回复。我已经按照你的方式尝试过了,正如你所说的那样,它确实有效。这种方法的唯一缺点是我想将结果传递回调用线程。我在 MS 文档中看到他们通常将控件的 DataContext 设置为结果。
      • 尝试使用控件的Dispatcher对象从结果回调方法中设置其DataContext。
      猜你喜欢
      • 1970-01-01
      • 2010-12-11
      • 2010-09-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-06
      相关资源
      最近更新 更多