Suggestions to avoid certain timeouts and exceptions when using SOA
Avoiding Timeouts
In HPC 2008 (V2) SOA, a service call lasts more than 10 minutes will cause the broker closes the connection to the client. This will cause a timeout.
Example:
- Assume call durations may be longer than 10 minutes but shorter than 30 minutes.
- My service dll is SimpleService.dll
- My service name is SOATests.SoaSimpleService
- My service contract is SOATests.ISoaSimpleService
1. Client: add the following to the client code.
client.InnerChannel.OperationTimeout = TimeSpan.FromMinutes(30);
2. Service side.
Add a <serviceAssembly>.dll.config and deploy it together with the <serviceAssembly>.dll to all nodes.
Template:
<?xml version="1.0" encoding="utf-8" ?> <configuration> <system.serviceModel> <services> <service name=" < ServiceImplName> "> <endpoint binding="netTcpBinding" bindingConfiguration="ServiceBinding" name="tcpbinging0" contract=" < ServiceContractName> " /> </service> </services> <bindings> <netTcpBinding> <binding name="ServiceBinding" receiveTimeout="00:30:00" portSharingEnabled="true"> <security mode="Transport" /> </binding> </netTcpBinding> </bindings> </system.serviceModel> </configuration> |
Example: (file is called SimpleService.dll.config)
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="myBinding" receiveTimeout="00:30:00">
<security mode="Transport" />
</binding>
</netTcpBinding>
</bindings>
<services>
<service name="SOATests.SoaSimpleService">
<endpoint address="" binding="netTcpBinding"
bindingConfiguration="myBinding"
contract="SOATests.ISoaSimpleService"/>
</service>
</services>
</system.serviceModel>
</configuration>
Avoiding Exceptions
In HPC 2008 (V2) SOA, a service call that contains a big array (or list, or other type of collections), WCF might throw an exception - Exception:
The formatter threw an exception while trying to deserialize the message: There was an error while trying to deserialize parameter. 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.'
Solution:
This is because there are some built-in limits in WCF. This can be configured through app.config file. There are 2 config files that need to be changed.
1. Client side app.config. Find the binding you are using and add attributes like following sample.
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="maxitembehavior">
<dataContractSerializer maxItemsInObjectGraph="6553600"/>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<netTcpBinding>
<binding name="netTcpBindingConfiguration"
maxBufferSize="99000000"
maxReceivedMessageSize="99000000">
<readerQuotas maxDepth="900000"
maxStringContentLength="900000"
maxArrayLength="900000"
maxBytesPerRead="900000"
maxNameTableCharCount="900000" />
<security mode="Transport" />
</binding>
</netTcpBinding>
</bindings>
<client>
<endpoint name ="echosvcclient" binding ="netTcpBinding" bindingConfiguration ="netTcpBindingConfiguration" contract ="EchoSvcReference.IEchoSvc" behaviorConfiguration="maxitembehavior">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
</client>
</system.serviceModel>
2. The service assembly app.config (depending on your deployment it could be per Compute node or a file share. It’s called <service_assembly_name>.dll.config). Find the Net.tcp binding you are using and add those attributes. Following is an example:
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="EchoSvc.EchoSvcBehavior">
<dataContractSerializer maxItemsInObjectGraph="6553600" />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<netTcpBinding>
<binding name="myBinding"
maxBufferSize="99000000"
maxReceivedMessageSize="99000000"
receiveTimeout="00:30:00">
<readerQuotas maxDepth="900000"
maxStringContentLength="900000"
maxArrayLength="900000"
maxBytesPerRead="900000"
maxNameTableCharCount="900000" />
<security mode="Transport" />
</binding>
</netTcpBinding>
</bindings>
<services>
<service name="EchoSvc.EchoSvc" behaviorConfiguration="EchoSvc.EchoSvcBehavior">
<endpoint address="" binding="netTcpBinding"
bindingConfiguration="myBinding"
contract="EchoSvc.IEchoSvc"/>
</service>
</services>
</system.serviceModel>
For both configuration files, the key attribute is maxItemsInObjectGraph. But you also want to make sure the message size settings are adjusted according to the size of the object actually transported as parameter.
And here is how I create the service client from client side to use the client binding configuration and transport a big message:
using (Session session = Session.CreateSession(info))
{
EchoSvcClient client = new EchoSvcClient("echosvcclient", session.EndpointReference);
Dictionary<string, string> a = new Dictionary<string, string>();
for (int i = 0; i < 17000; i++)
a.Add(i.ToString(), "abc");
Dictionary<string, string> b = client.EchoArray(a);
client.Close();
}