WCF序列化65536大小限制的问题
在Silverlight+WCF RIA Service或者WCF Service的架构中,经常会遇到WCF序列化65536大小限制的问题。由于WCF RIA Service没有提供明确的异常信息和错误信息,所以往往构成误导。
WCF RIA Service没有提供准确的异常信息和错误原因
比如我就遇到Silverlight客户端调用WCF RIA Service失败,异常信息是:System.ServiceModel.DomainServices.Client.DomainOperationException: Load operation failed for query 'GetProducts'. Inner exception message: Timeout expired.,居然异常信息是超时TimeOut,难道调用WCF RIA Service需要这么多时间吗?
换了一个数据库和机器,还是Silverlight客户端调用WCF RIA Service失败,异常信息变为:System.ServiceModel.DomainServices.Client.DomainOperationException: Load operation failed for query 'GetProducts'. The remote server returned an error: NotFound. ---> System.ServiceModel.CommunicationException: The remote server returned an error: NotFound. 异常信息又变成了Server Not Found。
事实上,当客户端调用WCF服务的时候比如调用WCF 服务的*.svc地址时候比如http://localhost:8562/ClientBin/MyNameSpace-DomainServices-MyDomainService.svc/binary/GetProducts?model=&productCode=&type=mp,如果服务端*.svc发生了任何状况不能给出200的应答码,就会返回一个错误比如404,而*.svc没有这个404重定向,就给个Server NotFound的异常信息,真是令人崩溃。
打开诊断选项找到WCF内部异常原因
其实如果需要查看Domain Service和Client的异常信息,可以在Web.config打开诊断选项并且用WCF服务跟踪查看器(SvcTraceViewer.exe)查看错误日志:
1: <configuration>
2: <system.diagnostics>
3: <sources>
4: <source name="System.ServiceModel" switchValue="Information, ActivityTracing"
5: propagateActivity="true">
6: <listeners>
7: <add name="traceListener" type="System.Diagnostics.XmlWriterTraceListener"
8: initializeData= "C:\WCFLogs\Traces.svclog" />
9: </listeners>
10: </source>
11: </sources>
12: </system.diagnostics>
13: </configuration>
使用WCF Sevice Trace Viewer定位异常
我用WCF服务跟踪查看器(SvcTraceViewer.exe)查看了错误日志,发现不是Server Not Found错误,而是WCF序列化65536大小限制,错误信息是:There was an error while trying to serialize parameterhttp://tempuri.org/:GetProductsResult. The InnerException message was 'Maximum number of items that can be serialized or deserialized in an object graph is '65536'. Change the object graph or increase the MaxItemsInObjectGraph quota. '. Please see InnerException for more details.,下面是截图:
Stacktrace:
System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.SerializeParameterPart(XmlDictionaryWriter writer, PartInfo part, Object graph)
System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.SerializeParameter(XmlDictionaryWriter writer, PartInfo part, Object graph)
System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.SerializeBody(XmlDictionaryWriter writer, MessageVersion version, String action, MessageDescription messageDescription, Object returnValue, Object[] parameters, Boolean isRequest)
System.ServiceModel.Dispatcher.OperationFormatter.SerializeBodyContents(XmlDictionaryWriter writer, MessageVersion version, Object[] parameters, Object returnValue, Boolean isRequest)
System.ServiceModel.Dispatcher.OperationFormatter.OperationFormatterMessage.OperationFormatterBodyWriter.OnWriteBodyContents(XmlDictionaryWriter writer)
System.ServiceModel.Channels.BodyWriter.WriteBodyContents(XmlDictionaryWriter writer)
System.ServiceModel.Channels.BodyWriterMessage.OnWriteBodyContents(XmlDictionaryWriter writer)
System.ServiceModel.Channels.Message.OnWriteMessage(XmlDictionaryWriter writer)
System.ServiceModel.Channels.Message.WriteMessage(XmlDictionaryWriter writer)
System.ServiceModel.DomainServices.Hosting.PoxBinaryMessageEncodingBindingElement.PoxBinaryMessageEncoder.WriteMessage(Message message, Int32 maxMessageSize, BufferManager bufferManager, Int32 messageOffset)
System.ServiceModel.Channels.HttpOutput.SerializeBufferedMessage(Message message)
System.ServiceModel.Channels.HttpOutput.Send(TimeSpan timeout)
System.ServiceModel.Channels.HttpRequestContext.OnReply(Message message, TimeSpan timeout)
System.ServiceModel.Activation.HostedHttpContext.OnReply(Message message, TimeSpan timeout)
System.ServiceModel.Channels.RequestContextBase.Reply(Message message, TimeSpan timeout)
System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.Reply(MessageRpc& rpc)
System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage9(MessageRpc& rpc)
System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage8(MessageRpc& rpc)
System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc)
System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage41(MessageRpc& rpc)
System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage4(MessageRpc& rpc)
System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage31(MessageRpc& rpc)
System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage3(MessageRpc& rpc)
System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage2(MessageRpc& rpc)
System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage11(MessageRpc& rpc)
System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage1(MessageRpc& rpc)
System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)
System.ServiceModel.Dispatcher.ChannelHandler.DispatchAndReleasePump(RequestContext request, Boolean cleanThread, OperationContext currentOperationContext)
System.ServiceModel.Dispatcher.ChannelHandler.HandleRequest(RequestContext request, OperationContext currentOperationContext)
System.ServiceModel.Dispatcher.ChannelHandler.AsyncMessagePump(IAsyncResult result)
System.ServiceModel.Dispatcher.ChannelHandler.OnAsyncReceiveComplete(IAsyncResult result)
System.Runtime.Fx.AsyncThunk.UnhandledExceptionFrame(IAsyncResult result)
System.ServiceModel.Diagnostics.TraceUtility.<>c__DisplayClass4.<CallbackGenerator>b__2(AsyncCallback callback, IAsyncResult result)
System.Runtime.AsyncResult.Complete(Boolean completedSynchronously)
System.Runtime.InputQueue`1.AsyncQueueReader.Set(Item item)
System.Runtime.InputQueue`1.EnqueueAndDispatch(Item item, Boolean canDispatchOnThisThread)
System.Runtime.InputQueue`1.EnqueueAndDispatch(T item, Action dequeuedCallback, Boolean canDispatchOnThisThread)
System.ServiceModel.Channels.SingletonChannelAcceptor`3.Enqueue(QueueItemType item, Action dequeuedCallback, Boolean canDispatchOnThisThread)
System.ServiceModel.Channels.HttpChannelListener.HttpContextReceived(HttpRequestContext context, Action callback)
System.ServiceModel.Activation.HostedHttpTransportManager.HttpContextReceived(HostedHttpRequestAsyncResult result)
System.ServiceModel.Activation.HostedHttpRequestAsyncResult.HandleRequest()
System.ServiceModel.Activation.HostedHttpRequestAsyncResult.BeginRequest()
System.ServiceModel.Activation.HostedHttpRequestAsyncResult.OnBeginRequest(Object state)
System.ServiceModel.AspNetPartialTrustHelpers.PartialTrustInvoke(ContextCallback callback, Object state)
System.ServiceModel.Activation.HostedHttpRequestAsyncResult.OnBeginRequestWithFlow(Object state)
System.Runtime.IOThreadScheduler.ScheduledOverlapped.IOCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* nativeOverlapped)
System.Runtime.Fx.IOCompletionThunk.UnhandledExceptionFrame(UInt32 error, UInt32 bytesRead, NativeOverlapped* nativeOverlapped)
System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)
解决办法
既然问题已经明确是WCF序列化和反序列化的65536大小限制导致Silverlight客户端接收不到,那就调整这个参数,异常信息已经给出提示可以配置MaxItemsInObjectGraph这个参数。我们修改Web.config即可:
1: <configuration>
2: <system.serviceModel>
3:
4: <serviceHostingEnvironment aspNetCompatibilityEnabled="true"
5: multipleSiteBindingsEnabled="true" />
6:
7: <!--设置 maxItemsInObjectGraph -->
8: <services>
9:
10: <!--注意下面这个name属性,必须改成你自己的namespace+DomainService类名!! -->
11: <service name="MyNamespace.MyDomainServiceClass"
12: behaviorConfiguration="MyWCFConfig" />
13: </services>
14: <behaviors>
15: <serviceBehaviors>
16: <behavior name="MyWCFConfig">
17: <dataContractSerializer maxItemsInObjectGraph="2147483647" />
18: </behavior>
19: </serviceBehaviors>
20: </behaviors>
21:
22: </system.serviceModel>
23: </configuration>
上面是最简单的配置方法,当然你的WCF如果很复杂,建议配置binding, endpoint等等,关于WCF配置Web.config,参考这个和这个。在SilverlightChina上专家MVP有这个帖子解决同样问题的,我使用下来不管用,而且没说明怎么调试问题。