我有一个WCF服务,它使用LinqToSql DataContext从数据库中获取一些信息。操作的返回类型是IEnumerable <DomainObject
&gt;,我有一个帮助器方法,它从Table派生的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
&gt;时会抛出SqlException。当序列化发生时。但是,当我在调试器中运行此代码时,我看到服务器端没有第一次机会异常!我告诉调试器在Exceptions选项卡中打破所有抛出的CLR异常,但它根本没有。我也没有在“输出”窗口中看到特有的“第一次机会异常”消息。
在客户端,我收到一条CommunicationException,其中包含“套接字连接意外终止”的错误消息。没有任何内部异常提供关于问题的根本原因的任何暗示。
我能解决这个问题的唯一方法是重写LINQ代码,以便在OperationContract方法内部计算查询表达式。顺便说一句,如果存在权限问题,或者我将DataContext包装在using语句中,我会得到相同的结果,所以这不仅仅与SqlExceptions隔离。
忽略使返回类型成为IEnumerable <T
&gt;的不可取之处。并且只在序列化程序的深处某处枚举查询,WCF是否抑制或以某种方式阻止在这种情况下抛出异常?如果是这样,为什么?
答案 0 :(得分:1)
至少根据我的经验,WCF看起来似乎做了一些异常的魔术。我真的不确定它对异常有什么作用,但我发现如果使用FaultContract属性指定合同可以抛出的异常,它至少会向客户端提供更多信息,说明错误的原因发生。
我们还会捕获任何异常并将它们作为FaultExceptions抛出,例如:
try
{
DoSomething();
}
catch ( Exception ex )
{
throw new FaultException<CustomException>( new CustomException( ex ), ex.Message );
}
在故障合同中指定自定义异常的位置。这似乎为客户提供了有关异常的更多信息。所以我怀疑如果你将SQLException作为FaultContract的一部分添加,那么它将被发送到客户端。
答案 1 :(得分:1)
是WCF抑制还是以某种方式阻止在这种情况下抛出异常?如果是这样,为什么?
我对WCF了解不多,但对我来说听起来不太可能。
关于第一次机会异常的特殊之处在于它直接进入调试器并且调试器有机会在实际引发异常之前看到它 - 因此“第一次机会”这个词 - 调试器具有处理异常的“第一次机会”。怎么可能绕过它呢?它必须是某种方式来阻止完全引发的异常。 (CLR中是否有安全性或可靠性功能可以执行此操作?)。
我可以提出的最佳替代解释是,在您希望抛出SqlException之前出现问题。我还会尝试查看非托管异常,而不仅仅是托管异常,以防万一例如尝试使用托管IEnumerable或某些CLR错误的非托管序列化代码出错...
答案 2 :(得分:0)
您是否配置了“IncludeExceptionDetailInFaults”设置? (出于安全考虑,它默认为'false'。
答案 3 :(得分:0)
WCF是一种好奇的野兽,它在常规IIS之外存在;可能是标准调试变得很糟糕。但是,您可以尝试enabling debug exceptions和/或实施(并配置)您自己的IErrorHandler
来记录问题。
另一种选择:在这里的某个地方可能有一个迭代器块(yield return
)吗?迭代器块中的 Nothing 在迭代枚举器之前被评估,这可能导致一些奇怪的问题,这些问题应该先前已经过验证。在上面的情况中,这不是一个问题(没有yield return
),但它是值得关注的。
例如,以下非常不同:
var context = CreateDataContext();
var query = from domainObject in context.DomainObjects
select ConvertDomainObject(domainObject);
foreach(var item in query) { yield return item; }
答案 4 :(得分:0)
尝试在客户端和服务的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附带的服务跟踪查看器中加载生成的日志文件。您将能够看到以这种方式抛出的实际异常。