Visual Studio打破了使用未处理的异常对话框处理的异常

Kas*_*erg 5 c# debugging unhandled-exception visual-studio

我的代码调用了当前未运行的WCF服务。所以我们应该期待EndPointNotFoundException。using语句尝试对Close()导致a的异常连接进行故障处理CommunicationObjectFaultedException。在use块周围的try catch块中捕获了此异常:

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");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

注意,服务EndPoint使用新的Guid,因此它将永远不会监听服务。

IDummyService 是:

[ServiceContract]
interface IDummyService
{
    [OperationContract]
    string Echo(string e);
}
Run Code Online (Sandbox Code Playgroud)

这会导致Visual Studio调试器(Visual Studio Professional 2017 15.4.1)中断并显示“未处理的异常”弹出窗口: 屏幕快照:调试器中断并显示“ Exception Unhandled”弹出窗口 唯一的例外上的Visual Studio破裂是System.ServiceModel.CommunicationObjectFaultedException抓的代码。

步进继续执行表明catch(CommunicationObjectFaultedException ex)已达到。使用LinqPad运行演示还显示异常已按预期捕获。

我还尝试了显式(两次)关闭通道,而不是使用using-block:

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");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这仍然会导致调试器在该Close语句上中断。

我的例外设置System.ServiceModel.CommunicationObjectFaultedException未选中。(选中该选项后,Visual Studio会按预期中断,并显示“抛出异常”对话框而不是“未处理异常”对话框)。

当我启用“选项” \“调试” \“常规” \“仅启用我的代码”时,调试器不会中断。不过,我有async方法在异常应该离开我的代码,当我后来捕获异常await荷兰国际集团的Task。对于这些方法,我需要未选中“启用我的代码”;请参阅在Tasks中阻止Visual Studio打破异常

禁用“使用新异常助手”(如Jack Zhai-MSFT的建议),Visual Studio仍会中断,并且显示 禁用“使用新异常助手”时的屏幕快照异常对话框 该对话框提供了一些其他信息:

在跨越托管/本机边界之前不会捕获到该异常。

我怀疑using块可能会引入此托管/本地边界。

是什么原因导致调试器错误地中断,以及如何使调试器既不中断也不处理,CommunicationObjectFaultedException也不会在以后的处理程序async异常时中断?

Kas*_*erg 1

Close()-ing a会导致 a :Faulted IClientChannelCommunicationObjectFaultedException

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

--(请参阅.NET Framework 4.7 参考源中的CommunicationObject.Close(TimeSpan) 第 299 行)。

\n\n

-blockusing被转换为try { ... } finally { Dispose(); }并在该块离开时Dispose()调用。Close()返回的代理CreateChannel()是通过RealProxysrc)实现的,RemotingServices.CreateTransparentProxy()这些代理结合了托管和非托管代码,这可能会导致跨越边界的异常。

\n\n

设置组合(在“工具”->“选项”->“调试器”->“常规”中):

\n\n
    \n
  • \xe2\x98\x91 当异常跨越 AppDomain 或托管/本机边界时中断
  • \n
  • \xe2\x98\x90 仅启用我的代码
  • \n
\n\n

导致 Visual Studio 中断显示:新的非模式异常弹出窗口“Exception Unhandled”:\n屏幕截图:Visual Studio:异常未处理(新异常处理程序)或模式对话框:\n屏幕截图:Visual Studio 因跨越 AppDomain 或托管/本机边界的异常而中断

\n\n

开头CommunicationObjectFaultedException为“不是我的代码”;它跨越托管/非托管或 AppDomain 边界,同时仍处于“不是我的代码”中;最后进入“我的代码”,由 -block 处理catch(但此时 Visual Studio 已经停止执行)。
\n由于异常从“不是我的代码”开始,并在跨越边界时保留在那里,因此选择“仅启用我的代码”选项会导致 Visual Studio 不会因异常而中断,即使它跨越 AppDomain 或托管/非托管边界。
\n取消选择“异常跨越 AppDomain 或托管/本机边界时中断”也会导致 Visual Studio 不会在异常时中断。

\n\n

这提供了两种解决方案/解决方法

\n\n\n