代码之家  ›  专栏  ›  技术社区  ›  Scrappydog

在.NET中实现嵌套异步“调用堆栈”方案

  •  1
  • Scrappydog  · 技术社区  · 17 年前

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

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

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

    第页->GetPersonRequest->PersonBusinessRequest->个人数据请求->WebserviceRequest

    第<页GetPersonResponse<-PersonBusinessResponse<-PersonDataResponse<-Web服务响应

    核心问题:

    1. 这是一个糟糕的想法吗?我真的应该用一个更异步的视角从头重写它吗?

    2. 假设采用这种方法,如何为嵌套响应保留调用堆栈?

    短暂性脑缺血发作-

    -埃里克

    2 回复  |  直到 17 年前
        1
  •  2
  •   MichaelGG    17 年前
    1. 您不能阻止主Silverlight线程,否则您的UI将挂起。这就是SL中所有网络操作都是强制异步的原因。

    这是两个制约因素。我的方法是创建一个“异步包装器”函数来为您包装它。这将需要3个功能(代表): 1.在新线程(“f”)上执行(确保在函数中未捕获任何UI对象!) 2.在异常情况下执行(“econt”)

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

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

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

    static void AsyncHelp<T>(Func<T> f, Action<Exception> econt, Action<T> cont) {
      var t = new Thread((_) => {
        try {
          var res = f();
          System.Windows.Deployment.Current.Dispatcher.BeginInvoke(() => cont(res));
        } catch (Exception ex) {
          System.Windows.Deployment.Current.Dispatcher.BeginInvoke(() => econt(ex));
        }
      });
      t.Start();
    }
    

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

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

    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
    
        2
  •  0
  •   mbeckish    17 年前

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

    1. 发出异步请求后,对ManualResetEvent执行WaitOne()。
    2. 在回调中,对ManualResetEvent执行Set()。

    http://msdn.microsoft.com/en-us/library/system.net.webrequest.endgetrequeststream.aspx