问题
I have a WCF service running that is attempting to return a DataTable
. The service method uses a SqlDataReader
, and then uses DataTable.Load()
to get that data into the DataTable
it intends to return.
Problem: when the service method returns a large table (I'll define this in a moment), I get these exceptions in the debug output (they do not cripple the service):
A first chance exception of type 'System.OutOfMemoryException' occurred in SMDiagnostics.dll
A first chance exception of type 'System.InsufficientMemoryException' occurred in SMDiagnostics.dll
Definition of "Large": the returned record set in my testing contains 286760 records and when this table is exported out to text, it's roughly 800MB in size. I know this is all relative, so that might all be meaningless. Mostly, I point this out because this seems rather small to me to be throwing memory exceptions, especially in light of the fact that the development machine on which I'm testing has 8GB of memory. Again, it's all relative, and perhaps irrelevant, but I'm trying to provide enough information.
Here is my connection code:
NetTcpBinding netBind = new NetTcpBinding();
netBind.Security.Mode = SecurityMode.Transport;
netBind.Security.Transport.ClientCredentialType = TcpClientCredentialType.Windows;
netBind.MaxReceivedMessageSize = Int32.MaxValue;
netBind.MaxBufferSize = Int32.MaxValue;
netBind.MaxBufferPoolSize = 0;
netBind.MaxConnections = 300;
netBind.ListenBacklog = 300;
netBind.ReaderQuotas = XmlDictionaryReaderQuotas.Max;
netBind.PortSharingEnabled = true;
netBind.OpenTimeout = new TimeSpan(0, 0, RegistryValues.DatabaseTimeout);
netBind.CloseTimeout = new TimeSpan(0, 0, RegistryValues.DatabaseTimeout);
netBind.ReceiveTimeout = new TimeSpan(0, 5, 0);
netBind.SendTimeout = new TimeSpan(0, 5, 0);
netBind.ReliableSession.InactivityTimeout = new TimeSpan(long.MaxValue);
netBind.TransferMode = TransferMode.Buffered;
uriBuilder = new UriBuilder("net.tcp", connServer, (connPort == -1 ? RegistryValues.ServerPort : connPort), "Data");
epAddress = new EndpointAddress(uriBuilder.Uri);
ChannelFactory<IData> iChannel = new ChannelFactory<IData>(netBind, epAddress);
iChannel.Credentials.Windows.AllowedImpersonationLevel = TokenImpersonationLevel.Identification;
IData svcCon = iChannel.CreateChannel();
((IClientChannel)svcCon).OperationTimeout = new TimeSpan(long.MaxValue);
Note, that we're using the Buffered
transfer mode. I'm considering the Streamed
alternative, but that will impose a radical structure change to the rest of the code...not something I want to do if there's a solution within the current model. I point back to the fact that I just don't think I'm pushing inordinate amounts of data.
This connection is established as part of the creation of a Sql
class object (my class). The iChannel
and svcCon
objects are disposed of together when the Sql.Dispose()
method is invoked (because we create these Sql
objects with a using
block).
Here's the Sql.Dispose()
method that my using
blocks should be triggering (in case it matters):
public void Dispose()
{
if (this != null && this.connection.State == ConnectionState.Open)
ClearConnectionPool();
try
{
if (iChannel.State != CommunicationState.Faulted)
iChannel.Close();
}
catch { iChannel.Abort(); }
try
{
if (((IClientChannel)svcCon).State != CommunicationState.Faulted)
((IClientChannel)svcCon).Close();
}
catch { ((IClientChannel)svcCon).Abort(); }
}
In summary, I am creating a WCF communication channel, which in turn creates a SqlConnection
. Using that, we fire off SQL calls. All of this is then disposed of as quickly as possible. We do not hang onto these connections for any longer than is necessary to perform the needed database operations. And there are very rare cases where these things are not created within using
blocks, meaning that I am quite sure we are cleaning up properly. Unless, of course, someone sees a problem with my Dispose()
method.
Any advice is appreciated. I can provide more code as requested.
Some additional information: here is the stack trace I receive when debugging the client and stepping into the server code to watch what happens when it attempts to return the DataTable
:
A first chance exception of type 'System.OutOfMemoryException' occurred in SMDiagnostics.dll
A first chance exception of type 'System.InsufficientMemoryException' occurred in SMDiagnostics.dll
A first chance exception of type 'System.Net.Sockets.SocketException' occurred in System.dll
Step into: Stepping over method without symbols 'System.ServiceModel.Dispatcher.MessageRpc.Process'
A first chance exception of type 'System.ServiceModel.CommunicationException' occurred in System.ServiceModel.dll
Step into: Stepping over method without symbols 'System.ServiceModel.Dispatcher.ChannelHandler.DispatchAndReleasePump'
A first chance exception of type 'System.IO.IOException' occurred in System.dll
Step into: Stepping over method without symbols 'System.ServiceModel.Dispatcher.ChannelHandler.HandleRequest'
Step into: Stepping over method without symbols 'System.ServiceModel.Dispatcher.ChannelHandler.AsyncMessagePump'
A first chance exception of type 'System.ServiceModel.CommunicationException' occurred in System.ServiceModel.dll
Step into: Stepping over method without symbols 'System.ServiceModel.Diagnostics.Utility.AsyncThunk.UnhandledExceptionFrame'
Step into: Stepping over method without symbols 'System.ServiceModel.AsyncResult.Complete'
A first chance exception of type 'System.ServiceModel.CommunicationException' occurred in mscorlib.dll
Step into: Stepping over method without symbols 'System.ServiceModel.Diagnostics.Utility.AsyncThunk.UnhandledExceptionFrame'
Step into: Stepping over method without symbols 'System.ServiceModel.AsyncResult.Complete'
A first chance exception of type 'System.ServiceModel.CommunicationObjectFaultedException' occurred in System.ServiceModel.dll
Step into: Stepping over method without symbols 'System.ServiceModel.Diagnostics.Utility.AsyncThunk.UnhandledExceptionFrame'
Step into: Stepping over method without symbols 'System.Net.LazyAsyncResult.Complete'
A first chance exception of type 'System.ServiceModel.CommunicationObjectFaultedException' occurred in mscorlib.dll
Step into: Stepping over method without symbols 'System.Net.Security.NegotiateStream.ProcessFrameBody'
A first chance exception of type 'System.ServiceModel.CommunicationObjectFaultedException' occurred in System.ServiceModel.dll
Step into: Stepping over method without symbols 'System.Net.Security.NegotiateStream.ReadCallback'
Step into: Stepping over method without symbols 'System.Net.FixedSizeReader.CheckCompletionBeforeNextRead'
Step into: Stepping over method without symbols 'System.Net.FixedSizeReader.ReadCallback'
Step into: Stepping over method without symbols 'System.ServiceModel.AsyncResult.Complete'
Step into: Stepping over method without symbols 'System.ServiceModel.Diagnostics.Utility.IOCompletionThunk.UnhandledExceptionFrame'
Step into: Stepping over method without symbols 'System.Threading._IOCompletionCallback.PerformIOCompletionCallback'
回答1:
Please verify dataContractSerializer attribute under behaviors section and increase the value to a greater value.
Also check readerQuotas section as well as maxBufferPoolSize, maxBufferSize and maxReceivedMessageSize attributes.
回答2:
Change your transfermode to streamed both web config and other config... u cant change web config transfermode unless you deploy it in your IIS
来源:https://stackoverflow.com/questions/18149465/need-help-resolving-an-error-when-wcf-service-returns-datatable-outofmemoryexce