WCF是否抑制首次机会异常



我有一个WCF服务,它使用LinqToSql DataContext从数据库中获取一些信息。操作的返回类型是IEnumerable <DomainObject>,我有一个助手方法,它可以从表派生的LINQ对象转换为WCF数据协定,如下所示:

[OperationContract]
public IEnumerable<DomainObjectDTO> RetrieveDomainObjects()
{
    var context = CreateDataContext();
    return from domainObject in context.DomainObjects
           select ConvertDomainObject(domainObject);
}
private DomainObjectDTO ConvertDomainObject(DomainObject obj)
{
    // etc...
}

如果我向DataContext传递了一个无效的连接字符串,则此代码会显示出一种奇怪的行为。由于无法找到正确的数据库,可能在进行序列化时,上面的代码在枚举IEnumerable <DomainObjectDTO>时引发SqlException。然而,当我在调试器中运行这段代码时,我在服务器端根本看不到第一次出现异常!我告诉"异常"选项卡中的调试器中断所有抛出的CLR异常,但它根本没有。我也没有在Output窗口中看到"First chance exception"消息。

在客户端,我得到一个CommunicationException,其中包含一条错误消息,行数为"套接字连接意外终止"。没有任何内部异常提供任何关于问题根本原因的提示。

我能弄清楚这一点的唯一方法是重写LINQ代码,使查询表达式在OperationContract方法内部求值。顺便说一句,如果存在权限问题,或者如果我将DataContext封装在using语句中,我会得到相同的结果,所以这不仅仅是与SqlExceptions隔离的。

忽略了将返回类型设置为IEnumerable <T>并仅枚举序列化程序深处某个位置的查询的不可取性,WCF在这种情况下是在抑制还是以某种方式防止抛出异常?如果是,为什么?

WCF似乎确实有一些神奇之处,至少在我的经验中是这样。我真的不确定它对异常做了什么,但我发现,如果FaultContract属性用于指定合约可能引发的异常,它至少会向客户端提供更多关于错误发生原因的信息。

我们还将捕获任何异常,并将其作为FaultException重新抛出,类似于:

try
{
    DoSomething();
}
catch ( Exception ex )
{ 
   throw new FaultException<CustomException>( new CustomException( ex ), ex.Message );
}

在故障合同中指定自定义异常的情况下。这似乎为客户端提供了更多有关异常的信息。所以我怀疑,如果您将SQLException作为FaultContract的一部分添加,那么它就会被发送到客户端。

在这种情况下,WCF是在抑制还是以某种方式防止抛出异常?如果是,为什么?

我对WCF了解不多,但听起来不太可能。

第一次机会异常的特殊之处在于,它直接进入调试器,调试器有机会在实际引发异常之前看到它,因此使用了"第一次机会"一词,调试器有"第一次时间"来处理异常。什么东西能绕过它?这必须是某种方式来完全阻止引发异常。(CLR中是否有安全性或可靠性功能可以做到这一点?)。

我能提出的最好的替代解释是,在您期望抛出SqlException的点之前出现了问题。我也会尝试查看非托管异常,而不仅仅是托管异常,以防出现这种情况。例如,在尝试使用托管IEnumerable的非托管序列化代码中出现问题,或者某些CLR错误。。。

您是否配置了"IncludeExceptionDetailInFaults"设置?(出于安全目的,它默认为"false")。

WCF是一个奇怪的野兽,它生活在常规IIS之外;可能是标准调试出现了故障。但是,您可以尝试启用调试异常,和/或实现(和配置)自己的IErrorHandler来记录问题。

另一个选项:这里的组合中是否有迭代器块(yield return在迭代枚举器之前,迭代器块中的任何东西都不会被求值,这可能会导致本应提前验证的数据出现一些奇怪的问题。在上面的例子中,这不是一个问题(没有yield return),但值得关注。

例如,以下是非常不同的

var context = CreateDataContext();
var query = from domainObject in context.DomainObjects
       select ConvertDomainObject(domainObject);
foreach(var item in query) { yield return item; }

尝试将以下内容放入客户端和服务的App.config中:

<system.diagnostics>
<sources>
    <source name="System.ServiceModel" switchValue="Verbose,ActivityTracing"
        propagateActivity="true">
        <listeners>
            <add type="System.Diagnostics.DefaultTraceListener" name="Default">
                <filter type="" />
            </add>
            <add name="NewListener">
                <filter type="" />
            </add>
        </listeners>
    </source>
</sources>
<sharedListeners>
    <add initializeData="C:App_tracelog.svclog"
        type="System.Diagnostics.XmlWriterTraceListener, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
        name="NewListener" traceOutputOptions="LogicalOperationStack, DateTime, Timestamp, ProcessId, ThreadId, Callstack">
        <filter type="" />
    </add>
</sharedListeners>

然后在Windows SDK附带的服务跟踪查看器中加载两个生成的日志文件。您将能够看到以这种方式抛出的实际异常。

链接:http://msdn.microsoft.com/en-us/library/aa751795.aspx

相关内容

  • 没有找到相关文章

最新更新