2011-09-29 78 views
2

我已经知道,通过调用到Silverlight的WCF服务是异步。我也知道,很多人想方设法让他们出于各种原因傻(阻塞例如UI线程)同步调用,这样的事情应该避免像瘟疫,一般。Silverlight和同步调用WCF

我只是希望能够处理所有的线程的东西我自己,因为我已经发现具有挂钩/脱钩所有的“*已完成”的事件是很多额外的工作,和一个巨大的痛苦,尤其是当你不知道电话的顺序等。任何人都知道一个聪明的方式来进行同步呼叫,并自己做线程?

+0

你为什么解开所有的“完成”事件? – ChrisF

+0

为了避免内存泄漏。简而言之,服务'A'可以在多个位置被调用,并且有时它的'Completed'事件没有完全相同的处理程序。但是,让我们避免设计/意图讨论,并坚持问题的技术部分.... –

+0

公平的,但知道设计/意图可以影响解决方案。 – ChrisF

回答

3

既然你不应该同步网络电话,你不应该做同步的网络电话,你不应该做同步的网络电话,如果你真的知道你在做什么,那么你实际上可以使仅当您不在UI线程中时才会同步(阻止)调用。只是意识到它不是一个官方支持的场景(所以它不像其他功能那样经过测试),但我已经尝试了几次,它只是起作用。

您只需要使用[ServiceContract]界面(而不是客户端类) - 一个暴露开始/结束操作的界面 - 并且调用EndXXX(BeginXXX(parameters, null, null))(如下例所示)(这是一个带有两个控件的页面,一个ButtonClick事件被绑定到Button_Click处理程序,一个名为“txtDebug” TextBox其中代码写入结果。

public partial class MainPage : UserControl 
{ 
    public MainPage() 
    { 
     InitializeComponent(); 
    } 

    private void Button_Click(object sender, RoutedEventArgs e) 
    { 
     this.AddToDebug("In Button_Click"); 
     ThreadPool.QueueUserWorkItem(delegate 
     { 
      ServiceReference1.Service1Client client = new ServiceReference1.Service1Client(); 
      ServiceReference1.Service1 asInterface = client; 
      this.AddToDebug("Calling server \"synchronously\"..."); 
      int result = asInterface.EndAdd(asInterface.BeginAdd(45, 67, null, null)); 
      this.AddToDebug("Result: {0}", result); 
      client.CloseAsync(); 
     }); 
    } 

    private void AddToDebug(string text, params object[] args) 
    { 
     if (args != null && args.Length > 0) 
     { 
      text = string.Format(text, args); 
     } 

     text = string.Format("[{0} - {1}] {2}", Thread.CurrentThread.ManagedThreadId, DateTime.Now.ToString("HH:mm:ss.fff"), text); 

     this.Dispatcher.BeginInvoke(() => this.txtDebug.Text = this.txtDebug.Text + text + Environment.NewLine); 
    } 
} 

现在,如果你想从UI线程做,那么真,没有办法阻止和等待响应(因为响应也应该在UI线程上返回)。如果你conf可以使用开始/结束模式,您仍然可以执行异步调用,但不用担心事件处理程序被泄露。

+0

是的,我永远不想阻止UI线程,只是避免了'普通'Silverlight方法的开销。这看起来像它会带我走向正确的方向...... –

+0

你真的在Silverlight中试过这个吗?由于Silverlight在IAsyncResult的实现上不支持AsyncWaitHandles,所以很难看出它是如何工作的?我并不是说它绝对不是我自己没有尝试过的,但如果它真的发生了,我真的很惊讶。 – AnthonyWJones

+0

是的,我在回复之前尝试过。正如我所说,它不被支持,但在简单的情况下,我尝试了它的工作,所以这是一个“使用风险自负”黑客攻击。 – carlosfigueira

-1

如果换在另一个函数调用,而函数会睡觉,直到异步调用返回的是什么?

+0

这基本上是我现在正在做的,但它仍然不能避免挂钩/解除钩住事件的代码开销。 –

1

解决方案依赖于阻塞线程(任何线程不只是UI线程),最好避免。线程是昂贵的资源,并且ThreadPool线程是有限的资源。这就是为什么网络API首先具有回调语义。

我同意Carlos首先要做的是切换到服务提供的.NET异步模式接口,而不是基于可怕的事件。 (基于事件的方法旨在让“事件思考”的UI开发人员变得简单)。如果你的服务被称为“Service1”,你的客户端类将被称为“Service1Client”。但是,该类还将支持名为“Service1”的接口,该接口将具有OperationContracts的开始/结束版本。

“一个聪明的办法,使同步调用”

没有阻塞线程,这是不可能的。然而,使一系列同步任务不是真正的要求。我们要的只是是为了确保一系列任务发生在序列。你可以简单地通过从前一个任务的回调方法中调用下一个任务来完成这一任务,但是嵌套成为一个问题。

看看这个系列的articles也许从.NET Asynchronous Pattern上的一个开始。不幸的是,WCF的一篇文章仍在进行中,但我很快就会发布它,这些内容经常会出现在这里。