C# Visual studio在使用“未处理的异常”对话框处理异常时中断

C# Visual studio在使用“未处理的异常”对话框处理异常时中断,c#,visual-studio,debugging,unhandled-exception,C#,Visual Studio,Debugging,Unhandled Exception,我的代码调用当前未运行的WCF服务。因此,我们应该期待未来。using语句尝试删除导致异常的错误连接。在使用块周围的try-catch块中捕获此异常: class Program { static void Main() { try { using (ChannelFactory<IDummyService> unexistingSvc = new ChannelFactory<IDummyService&

我的代码调用当前未运行的WCF服务。因此,我们应该期待未来。using语句尝试删除导致异常的错误连接。在使用块周围的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");
        }
    }
}
这会导致Visual Studio调试器(Visual Studio Professional 2017 15.4.1)中断,并出现“异常未处理”弹出窗口: Visual Studio中断的异常是
System.ServiceModel.CommunicationObjectFaultedException
,它被捕获在代码中

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

我还尝试显式(双重)关闭通道,而不是使用
块:

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");
        }
    }
}
类程序
{
静态void Main()
{
尝试
{
使用(ChannelFactory unexistingSvc=newchannelfactory(new NetNamedPipeBinding(),“net。pipe://localhost/UnexistingService-“+Guid.NewGuid().ToString()))
{
IDummyService chan=null;
尝试
{
chan=unexistingSvc.CreateChannel();
chan.Echo(“你好”);
}
捕获(EndpointNotFoundException ex)
{
WriteLine($“应为:{ex.Message}”);
}
最后
{
尝试
{
(chan作为IClientChannel)?.Close();
}
捕获(通信对象故障异常异常)
{
WriteLine($”由Close:{ex.Message}引起);
}
}
}
}
捕获(EndpointNotFoundException ex)
{
Console.WriteLine(“预期”);
}
捕获(通信对象故障异常异常)
{
WriteLine(“预期:由关闭引发EndPointNotFoundException的通道引起”);
}
}
}
这仍然会导致调试器在
Close
语句上中断

我的异常设置未选中System.ServiceModel.CommunicationObjectFaultedException
。(选中该选项后,Visual studio将按预期中断,并使用“异常引发”对话框而不是“异常未处理”对话框)

当我启用“选项”\“调试”\“常规”\“仅启用我的代码”时,调试器不会中断。但是,我有
async
方法,其中异常应该离开我的代码,然后在
等待
任务时捕获异常。对于这些方法,我需要取消选中“仅启用我的代码”;看

禁用“使用新异常帮助器”(如建议的)后,VisualStudio仍会中断并显示 该对话框提供了一些附加信息:

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

我怀疑using块可能引入了这个托管/本机边界


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

新的异常功能在VS2017中,我们可以禁用调试选项“使用新的异常帮助程序”在工具->选项->调试->常规下,您可以访问它,该工具可以为您提供旧的异常消息

旧异常消息显示异常跨越托管/本机边界:

选中“工具->选项->调试->常规”下的“异常跨越AppDomain或托管/本机边界时中断”。禁用“异常跨越AppDomain或托管/本机边界时中断”以避免Visual Studio在OP的情况下中断(但要小心,因为这也会在异常跨越AppDomain或托管/本机边界的其他情况下禁用中断)。

-ing a会导致:

--(见中的)

using
-块被转换为
try{…}finally{Dispose();}
,并在块离开时调用。由返回的代理通过()实现,这些代理将托管代码和非托管代码结合起来,这可能会导致异常跨越边界

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

  • ☑ 异常跨越AppDomain或托管/本机边界时中断
  • ☐ 仅启用我的代码
导致Visual Studio中断显示:新的非模式异常弹出窗口“异常未处理”: 或模式对话框:

以“非我的代码”开头;它跨越托管/非托管或AppDomain边界,但仍处于“非我的代码”状态;最后输入“我的代码”,由catch-块处理(但Visual Studio此时已停止执行)。
由于异常从“非我的代码”开始,并在跨越边界时保持不变,因此选择“仅启用我的代码”选项会导致Visual studio即使跨越AppDomain或托管/非托管边界也不会中断异常。
取消选择“异常跨越AppDomain或托管/本机边界时中断”也会导致Visual Studio在异常时不中断

这提供了两种解决方案/变通方法
  • 选择“异常跨越AppDomain或托管/本机边界时中断”和“仅启用我的代码”的不同组合
  • 请勿使用<代码>使用<代码>-块进行检查。正如在

如果在VS2017中禁用“工具->选项->调试->常规”下的调试选项“使用新异常帮助器”,那么
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");
        }
    }
}
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;
        ...
    }
    ...
}