C# - AsyncCallback中的异常传播问题

时间:2011-11-15 13:05:35

标签: c# .net

以下代码非常明确,我的问题非常简单:
为什么AsyncCallback方法“HandleConnect”没有将异常传播到“Connect”方法
以及如何传播它?

    public void Connect(IPEndPoint endpoint, IVfxIpcSession session)
    {
        try 
        {  
          ipcState.IpcSocket.BeginConnect(ipcState.IpcEndpoint, HandleConnect, ipcState);  
        }

        catch(Exception x) 
        { 
          ManageException(x.ToString()); //Never Caught, though "HandleConnect" blows a SocketException
        }
    }

    private void HandleConnect(IAsyncResult ar) 
    {
      // SocketException blows here, no propagation to method above is made. 
      // Initially there was a try/catch block that hided it and this is NOT GOOD AT ALL 
      // as I NEED TO KNOW when something goes wrong here.
       ipcState.IpcSocket.EndConnect(ar);  
    }


1 - 我想这是非常正常的行为。但我希望能够全面解释为什么会发生这种情况以及发生在幕后的情况。

2 - 是否有通过我的应用传播异常的快捷方式?

预警我知道这里的很多家伙非常关键,我期待评论“你为什么不把ManageException直接放在”HandleConnect“方法中。好吧,长话短说,我们只是说“我得到了我的理由”大声笑。我刚刚在这里发布了一个代码示例,我想比这更广泛地传播这种异常,并且做了比“N-upper”代码中其他地方更多的东西。< / p>

编辑
作为评论的评论,我之前也尝试过这个,没有运气:

    private void HandleConnect(IAsyncResult ar) 
    {          
        try 
        {
          ipcState.IpcSocket.EndConnect(ar);  
        }

        catch(Exception x) 
        { 
          throw x; // Exception Blows here. It is NOT propagated.
        }
    }

我的解决方案: 我最终放了一个事件处理程序,每个相关的代码逻辑都订阅了它 这样,异常不仅会被吞没,也不会被打击,而是会广播通知。

 public event EventHandler<MyEventArgs> EventDispatch;
 private void HandleConnect(IAsyncResult ar) 
    {          
        try 
        {
          ipcState.IpcSocket.EndConnect(ar);  
        }

        catch(Exception x) 
        {               
           if (EventDispatch!= null)
           {
               EventDispatch(this, args);
           }
        }
    }

  //Priorly, I push subscriptions like that : 

  tcpConnector.EventDispatch += tcpConnector_EventDispatch;

  public void tcpConnector_EventDispatch(object sender, VfxTcpConnectorEventArgs args)
  {
        //Notify third parties, manage exception, etc.
  }

这有点弯曲,但效果很好

3 个答案:

答案 0 :(得分:5)

使用BeginConnect时,连接是异步完成的。您将获得以下事件链:

  1. Connect“发布”通过BeginConnect连接的请求。
  2. Connect方法返回。
  3. 连接在后台完成。
  4. HandleConnect由框架调用,带有连接结果。
  5. 当您到达第4步时,Connect已经返回,因此try-catch块不再处于活动状态。这是使用异步实现时的行为。

    Connect中发现异常的唯一原因是BeginConnect无法启动后台连接任务。这可以是例如如果BeginConnect在启动后台操作之前验证提供的参数,并在它们不正确时抛出异常。

    您可以使用AppDomain.UnhandledException事件捕获中心位置的任何未处理的异常。一旦异常达到该级别,任何形式的恢复都可能很难实现,因为异常可能来自任何地方。如果您有恢复方法 - 尽可能接近原点捕获异常。如果您只记录/通知用户 - 一次集中捕获通常会更好。

答案 1 :(得分:2)

一种选择是将AsyncWaitHandle与现有代码一起使用。

为了更好地处理异常,您必须使用基于事件的编程模型或修改代码以使用BackgroundWorker组件,该组件支持从工作线程到主线程的报告错误。

在以下链接中有关于此主题的一些讨论和文章:

http://openmymind.net/2011/7/14/Error-Handling-In-Asynchronous-Code-With-Callbacks/

MSDN示例:http://msdn.microsoft.com/en-us/library/ms228978.aspx

答案 2 :(得分:1)

除了安德斯指出的内容之外,阅读本文可能是一个好主意:

http://msdn.microsoft.com/en-us/library/2e08f6yc.aspx

并研究如何使用AsyncCallback之类的方式将回调方法传递给对BeginConnect的异步调用(如果确实存在),您可以在其中检索委托并在try catch块中调用EndInvoke。

E.g:

    public void
    CallbackMethod
        (IAsyncResult AR)
    {
        // Retrieve the delegate
        MyDelegate ThisDelegate =
            (MyDelegate)AR.AsyncState;

        try
        {
            Int32 Ret = ThisDelegate.EndInvoke(AR);
        } // End try
        catch (Exception Ex)
        {
            ReportException(Ex);
        } // End try/catch
    } // End CallbackMethod