2017-10-20 175 views
4

我的代碼調用當前未運行的WCF服務。所以我們應該期待EndPointNotFoundException。使用聲明嘗試Close()故障的連接,導致除外的CommunicationObjectFaultedException。該例外被捕獲在使用塊周圍try catch塊:Visual Studio在處理異常異常時出現異常,處理異常對話框

class Program 
{ 
    static void Main() 
    { 
     try 
     { 
      using (ChannelFactory<IDummyService> unexistingSvc = new ChannelFactory<IDummyService>(new NetNamedPipeBinding(), "net.pipe://localhost/UnexistingService-" + Guid.NewGuid().ToString())) 
      { 
       using (IClientChannel chan = (unexistingSvc.CreateChannel() as IClientChannel)) 
       { 
        (chan as IDummyService)?.Echo("Hello"); 
       } 
      } 
     } 
     catch (EndpointNotFoundException ex) 
     { 
      Console.WriteLine("Expected"); 
     } 
     catch (CommunicationObjectFaultedException ex) 
     { 
      Console.WriteLine("Expected: caused by closing channel that has thrown EndPointNotFoundException"); 
     } 
    } 
} 

注的服務端點使用新鮮的Guid所以它永遠不會有一個服務的聆聽。

IDummyService是:

[ServiceContract] 
interface IDummyService 
{ 
    [OperationContract] 
    string Echo(string e); 
} 

這將導致Visual Studio調試器(Visual Studio的專業2017年15.4.1)與 「異常未處理」 彈出打破: Screen shot: Debugger breaking with Exception Unhandled popup 異常上的Visual Studio休息是System.ServiceModel.CommunicationObjectFaultedException其中在代碼中捕獲。

步進繼續執行表明已到達catch(CommunicationObjectFaultedException ex)。使用LinqPad運行演示也表明,異常被捕獲如預期。

我也試過明確(雙)關閉通道,而不是使用using - 阻塞的:

class Program 
{ 
    static void Main() 
    { 
     try 
     { 
      using (ChannelFactory<IDummyService> unexistingSvc = new ChannelFactory<IDummyService>(new NetNamedPipeBinding(), "net.pipe://localhost/UnexistingService-" + Guid.NewGuid().ToString())) 
      { 
       IDummyService chan = null; 
       try 
       { 
        chan = unexistingSvc.CreateChannel(); 
        chan.Echo("Hello"); 
       } 
       catch (EndpointNotFoundException ex) 
       { 
        Console.WriteLine($"Expected: {ex.Message}"); 
       } 
       finally 
       { 
        try 
        { 
         (chan as IClientChannel)?.Close(); 
        } 
        catch (CommunicationObjectFaultedException ex) 
        { 
         Console.WriteLine($"Caused by Close: {ex.Message}"); 
        } 
       } 
      } 
     } 
     catch (EndpointNotFoundException ex) 
     { 
      Console.WriteLine("Expected"); 
     } 
     catch (CommunicationObjectFaultedException ex) 
     { 
      Console.WriteLine("Expected: caused by closing channel that has thrown EndPointNotFoundException"); 
     } 
    } 
} 

這仍然使得調試器在Close聲明打破。

我的例外設置有System.ServiceModel.CommunicationObjectFaultedException未選中。 (當它被檢查時,Visual Studio按預期中斷並且使用「Exception Thrown」對話框而不是「Exception Unhandled」對話框)。

當我啓用「選項」\「調試」\「常規」\「啓用只是我的代碼」調試器不會中斷。然而,我有async方法,其中異常應該離開我的代碼,我後來發現 await。對於這些方法,我需要「啓用只是我的代碼」取消選中;見Stop visual studio from breaking on exception in Tasks

繼續「使用新的異常助手」已禁用(由Jack Zhai-MSFT建議)的Visual Studio仍然打破了,它顯示 Screenshot exception dialog when "Using the New Exception Helper" is disabled 對話框提供了一些額外的信息:

的異常沒有被捕獲它穿過前一個管理/本地邊界。

我懷疑使用塊可能會引入此託管/本機邊界。

是什麼導致調試器錯誤地中斷以及如何使調試器既不中斷也不處理CommunicationObjectFaultedException s也不對後來的處理器async異常?

+1

如果在VS2017的TOOLS-> OPTION-> Debugging-> General下禁用調試選項「使用新的異常幫助程序」,那麼結果如何? –

+0

@ JackZhai-MSFT我使用「使用新的例外助手」進行了測試,並將結果包括在問題中。舊的例外對話爲解決問題提供了一些新的途徑。 –

+0

@ JackZhai-MSFT謝謝,您的建議幫助我通過正確的設置解決問題。現在發佈答案。 –

回答

1

Close() -ing一個FaultedIClientChannel導致CommunicationObjectFaultedException

public void Close(TimeSpan timeout) 
{ 
    ... 
    switch (originalState) 
    { 
     case CommunicationState.Created: 
     case CommunicationState.Opening: 
     case CommunicationState.Faulted: 
      this.Abort(); 
      if (originalState == CommunicationState.Faulted) 
      { 
       throw TraceUtility.ThrowHelperError(this.CreateFaultedException(), Guid.Empty, this); 
      } 
      break; 
     ... 
    } 
    ... 
} 

- (參見在.NET framework 4.7 reference sourceCommunicationObject.Close(TimeSpan) line #299)。

using - 塊被轉換爲try { ... } finally { Dispose(); }Dispose()當塊被留下時調用Close()。由CreateChannel()返回的代理通過RealProxysrc)和RemotingServices.CreateTransparentProxy()執行,這些代理結合了託管代碼和非託管代碼,這些代碼可能會導致異常通過邊界。

的設置(在工具 - >選項> Debugger->一般)的組合:

  • ☑休息的時候例外交叉的AppDomain或管理/本地邊界
  • ☐啓用僅我的代碼

導致Visual Studio來打破要麼顯示:新的非模態的異常彈出「異常未處理」: Screenshot: Visual Studio: Exception Unhandled (New Exception Handler)或模態對話框: Screenshot: Visual studio breaking on exception that crosses AppDomain or managed/native boundary

CommunicationObjectFaultedException從'不是我的代碼'開始;它跨越了託管/非託管或AppDomain邊界,同時仍處於「不是我的代碼」中;並最終輸入'我的代碼',它由catch -block處理(但Visual Studio已經停止了此時的遷移)。
由於異常在「不是我的代碼」中開始,並且在穿越邊界時仍然存在,因此選擇「啓用我的代碼」選項會使Visual Studio在異常時不會中斷異常,即使它穿過AppDomain或管理/非管理邊界。
取消選擇「當異常跨AppDomain或託管/本地邊界時中斷」也會導致Visual Studio不會中斷異常。

這給出了兩個解決方案/變通方法

+0

我有EndPointNotFoundException相同的問題。這個設置爲我修好了!謝謝。 – z00mable

2

新的異常功能在VS2017中,我們可以在工具 - >選項 - >調試 - >常規下禁用調試選項「使用新的異常幫助程序」,它可以爲您提供舊的異常消息,您可以訪問它。

舊異常消息表明異常越過管理/天然邊界: Screenshot exception dialog when "Using the New Exception Helper" is disabled

檢查「打破時例外交叉應用程序域或管理/天然邊界」下工具 - >選項 - > Debugging->常規。禁用「異常中斷時跨越AppDomain或管理/本地邊界」以避免Visual Studio突破OP的情況(請小心,因爲這也會禁止打破異常跨越AppDomain或管理/本地邊界的其他情況)。