Visual Studio在处理异常异常时出现异常,处理异常对话框
我的代码调用当前未运行的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)与 “异常未处理” 弹出打破: 异常上的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仍然打破了,它显示 对话框提供了一些额外的信息:
的异常没有被捕获它穿过前一个管理/本地边界。
我怀疑使用块可能会引入此托管/本机边界。
是什么导致调试器错误地中断以及如何使调试器既不中断也不处理CommunicationObjectFaultedException
s也不对后来的处理器async
异常?
Close()
-ing一个Faulted
IClientChannel
导致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()
返回的代理通过RealProxy
(src)和RemotingServices.CreateTransparentProxy()
执行,这些代理结合了托管代码和非托管代码,这些代码可能会导致异常通过边界。
的设置(在工具 - >选项> Debugger->一般)的组合:
- ☑休息的时候例外交叉的AppDomain或管理/本地边界
- ☐启用仅我的代码
导致Visual Studio来打破要么显示:新的非模态的异常弹出“异常未处理”: 或模态对话框:
CommunicationObjectFaultedException
从'不是我的代码'开始;它跨越了托管/非托管或AppDomain边界,同时仍处于“不是我的代码”中;并最终输入'我的代码',它由catch
-block处理(但Visual Studio已经停止了此时的迁移)。
由于异常在“不是我的代码”中开始,并且在穿越边界时仍然存在,因此选择“启用我的代码”选项会使Visual Studio在异常时不会中断异常,即使它穿过AppDomain或管理/非管理边界。
取消选择“当异常跨AppDomain或托管/本地边界时中断”也会导致Visual Studio不会中断异常。
这给出了两个解决方案/变通方法
- 选择的不同组合“休息的时候例外交叉的AppDomain或管理/本地边界”和“启用仅我的代码”
- 做不在
Close()
之前使用using
-IClientChannel
和检查IClientChannel.State
。如在What is the best workaround for the WCF client `using` block issue?中所做的那样
我有EndPointNotFoundException相同的问题。这个设置为我修好了!谢谢。 – z00mable
如果在VS2017的TOOLS-> OPTION-> Debugging-> General下禁用调试选项“使用新的异常帮助程序”,那么结果如何? –
@ JackZhai-MSFT我使用“使用新的例外助手”进行了测试,并将结果包括在问题中。旧的例外对话为解决问题提供了一些新的途径。 –
@ JackZhai-MSFT谢谢,您的建议帮助我通过正确的设置解决问题。现在发布答案。 –