SerializationException not going to IErrorHandler



当试图反序列化一个相对较大的对象图(约10000行,上面有6列)时,我看到了奇怪的行为。我确信问题是当试图将此数组从服务反序列化回客户端时出现了序列化异常。它适用于少于9000个对象的数据集,控制台窗口显示第一次出现SerializationException,然后是CommunicationException。我在控制台应用程序中自行托管此服务,因为我使用它与第三方api集成。我的第一个问题是,有人知道是什么导致了这个系列化异常吗?

我在客户端和服务器上以以下方式配置代码中的绑定,我认为我已经尽可能地将其最大化了。

public static NetTcpBinding CreateStandardNetTcpBinding()
{
NetTcpBinding b = new NetTcpBinding(SecurityMode.None);
b.OpenTimeout = new TimeSpan(0, 5, 0);
b.ReceiveTimeout = new TimeSpan(0, 5, 0);
b.SendTimeout = new TimeSpan(0, 5, 0);
b.MaxReceivedMessageSize = Int32.MaxValue;
b.MaxBufferSize =(int) b.MaxReceivedMessageSize;
b.MaxBufferPoolSize = (int) b.MaxReceivedMessageSize;
b.TransferMode= TransferMode.Buffered;

b.ReaderQuotas.MaxNameTableCharCount = Int32.MaxValue;
b.ReaderQuotas.MaxArrayLength = Int32.MaxValue;
b.ReaderQuotas.MaxBytesPerRead = 4096;
b.ReaderQuotas.MaxStringContentLength = Int32.MaxValue;
b.ReaderQuotas.MaxDepth = 32;
return b;
}

我的第二个问题是,为什么这个异常没有在IErrorHandler接口上引发ProviderFault方法。当我从ServiceOperation中引发异常时,确实会引发ProviderFault方法。WCF框架异常不是也被IErrorHandler捕获吗?但对于这个特殊的问题,WCF似乎在捕捉到序列化异常后突然/立即关闭了通道(因此超时是不可能的)。

类型的第一次机会异常中发生"System.Runtime.Serialization.Serialization异常"System.Runtime.Serialization.dll类型的首次机会异常中发生"System.ServiceModel.CommunicationException"System.ServiceModel.dll

套接字连接已中止。这可能是由错误引起的处理您的消息或接收超时被远程主机或潜在的网络资源问题。本地插座超时为"00:04:59.8939894"。

我的第三个问题是,有人知道如何以编程方式添加WCF跟踪侦听器吗?我在插件环境中工作,应用程序没有专用的app.config文件。

谢谢!

---编辑---

是的,这就是问题所在。默认值是我所达到的64K左右。的解决方案

在servicebehavior属性中设置MaxItemsInObjectGraph值[ServiceBehavior(IncludeExceptionDetailInFaults=true,MaxItemsInObjectGraph=int.MaxValue)]

并在客户端上设置大小,就像这样…

var behaviors = Endpoint.Contract.Operations
.Select(o => o.Behaviors.Find<DataContractSerializerOperationBehavior>())
.Where(behavior => behavior != null);
foreach (var serializationBehavior in behaviors)
{
serializationBehavior.MaxItemsInObjectGraph = int.MaxValue;
}

不是100%确定,但我会在这里尝试一些答案。

您可能遇到了DataContractSerializer的MaxItemsInObjectGraph属性。但是,根据MSDN,默认值是Int32.MaxValue(2147483647),所以如果您还没有触及该值,我认为情况并非如此。

另一个选择可能是增加MaxDepth配额,但在这之前我的钱会在MaxItemsInObjectGraph上。

您是如何将创建的绑定分配给服务和客户端的?MSDN建议将此代码用于服务端:

OperationDescription operation = host.Description.Endpoints[0].Contract.Operations.Find("MyOperationName");
operation.Behaviors.Find<DataContractSerializerOperationBehavior>().MaxItemsInObjectGraph = 3;

不确定它将如何应用于客户端(没有深入研究)。

对于第二个问题,MSDN有点不清楚,但看起来IErrorHandler可能无法处理序列化错误:

Exceptions can occur after all ProvideFault implementations are called and a response message is handed to the channel. If a channel exception occurs (for example, difficulty serializing the message) IErrorHandler objects are notified. In this case, you should still make sure that your development environment catches and displays such exceptions to you or makes use of tracing to discover the problem. For more information about tracing, see Using Tracing to Troubleshoot Your Application.

对于您的最后一个问题,以编程方式启用WCF跟踪似乎是可能的,但有点复杂:如何在不使用配置文件的情况下(以编程方式)启用WCF跟踪?

不确定这些是否能解决你的问题,但希望它能给你一些探索的选择。

对于问题标题中描述的问题,可以使用IDispatchMessageInspector捕获SerializationException。

public class DispatcherExceptionHandler : IDispatchMessageInspector
{
public object AfterReceiveRequest(
ref Message request, 
IClientChannel channel, 
InstanceContext instanceContext) => null;
public void BeforeSendReply(ref Message reply, object correlationState)
{
try
{
reply.ToString();
}
catch (Exception e)
{
var faultCode = FaultCode.CreateSenderFaultCode(null);
var faultReason = new FaultReason(e.GetBaseException().Message);
reply = Message.CreateMessage(
reply.Version,
MessageFault.CreateFault(faultCode, faultReason),
null);
}
}
}

要设置检查器,请使用服务行为:

public class HandleDispatcherExceptionsServiceBehavior : IServiceBehavior
{
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
foreach (var dispatchRuntime in serviceHostBase.ChannelDispatchers.OfType<ChannelDispatcher>().SelectMany(ch => ch.Endpoints).Select(epd => epd.DispatchRuntime))
dispatchRuntime.MessageInspectors.Add(new DispatcherExceptionHandler());
}
// (...)
}

最新更新