.net 实现嵌套异步;调用堆栈“;NET中的场景

.net 实现嵌套异步;调用堆栈“;NET中的场景,.net,silverlight,web-services,architecture,.net,Silverlight,Web Services,Architecture,我正试图重构一些中等复杂的现有.NET代码,以便在Silverlight中使用。核心问题是,所有Silverlight web服务调用都必须是异步的,并且现有代码是以相当典型的同步方式实现的 典型操作的现有调用堆栈可能如下所示: some_handler() { var id = mytextbox.Text; // Save from UI to local AsyncHelp( () => GetBla(id), bla => result.Text

我正试图重构一些中等复杂的现有.NET代码,以便在Silverlight中使用。核心问题是,所有Silverlight web服务调用都必须是异步的,并且现有代码是以相当典型的同步方式实现的

典型操作的现有调用堆栈可能如下所示:

some_handler() {
  var id = mytextbox.Text; // Save from UI to local
  AsyncHelp( 
    () => GetBla(id), 
    bla => result.Text = bla.ToString(), // This is safe cause it's dispatched
    ex => error.Text = ex.ToString()
  );
}
Page->GetPersonMethod->PersonBusinessObject->PersonDataObject->CallWebservice->(气泡响应备份堆栈)

我的想法是将所有方法拆分为单独的请求和响应方法,并保留应用程序的整体结构

相同操作的新调用堆栈将如下所示:

some_handler() {
  var id = mytextbox.Text; // Save from UI to local
  AsyncHelp( 
    () => GetBla(id), 
    bla => result.Text = bla.ToString(), // This is safe cause it's dispatched
    ex => error.Text = ex.ToString()
  );
}
页面->GetPersonRequest->PersonBusinessRequest->PersonDataRequest->WebserviceRequest


Page为了避免重构,您可以将CallWebService实现为一种内部使用异步请求/响应的同步方法:

  • 发出异步请求后,对ManualResetEvent执行WaitOne()
  • 在回调中,对ManualResetEvent执行Set()
  • 您不能阻止主Silverlight线程,否则您的UI将挂起。这就是SL中所有网络操作都是强制异步的原因
  • 除了UI线程,您不能从任何线程触摸UI
  • 这是两个制约因素。我的方法是创建一个“异步包装器”函数来为您包装它。这将需要3个功能(代表): 1.在新线程(“f”)上执行(确保在函数中未捕获任何UI对象!) 2.在异常情况下执行(“econt”) 3.完成后执行(“续”)

    这两个continuation都将通过System.Windows.Deployment.Current.Dispatcher.BeginInvoke在UI线程上调度

    这样,您只需将web服务调用更改为“通过异步同步”,正如mbeckish所说(使用ManualResetEvent,来自同步线程的WaitOne,在回调上设置)

    帮助程序的代码可能如下所示(psuedocode,未检查):

    更新 要通过异步调用进行同步,您可以这样做,假设您使用默认的“基于事件的异步模式”(在我看来,使用BeginXXX/EndXXX更容易)


    从理论上讲,这是可能的,但我一直在读到,如果Silverlight应用程序在浏览器中的单个线程上运行,这是一个坏主意。。。意见?如果阻止主Silverlight线程,则UI将挂起。无论是Silverlight、WinForms还是ASP.NET,如果阻止,用户的UI线程都将挂起。我只是说,如果阻止UI线程在您以前的范例中起作用,那么在这里尝试它可能是值得的。这是一个很棒的代码,我很快就在测试应用程序中实现了它!非常有帮助!谢谢但我还没有完全明白如何让你的“通过异步同步”方案适用于异步Web服务调用。。。我的理解是Silverlight不支持WaitOne()?似乎表明WaitOne在那里。
    Exception ex;
    Result r;
    var mre = new ManualResetEvent(false);
    myService.OnGetBlaCompleted += (_, e) => {
      ex = e.Error;
      r = e.Result;
      mre.Set();
    }
    myService.GetBlaAsync(id);
    mre.WaitOne();
    if (ex != null) throw ex;
    // and so on