Thursday, September 23, 2010

How to set executionTimeout for individual requests?

You probably know that you can change http request processing timeout for specific page like this:
 <location path="MyLongRunningHttpHandler.ashx">
<system.web>
<httpRuntime executionTimeout="600" />
</system.web>
</location>
But what if you want to set it up for a control or just a function and do not have predefined list of pages to specify it in web.config?
Of maybe you don't want to pollute web.config with junk like that?

There should be some way to do it in C# code, right?
Right.
Here's how you do it:
    HttpContext.Current.Server.ScriptTimeout = 600; // 10 minutes
If that's what you were looking for, you probably want to test it.
I tried to test it too, and it turned out to be tricky.

First I set web.config's timeout to 2 seconds:
<httpRuntime executionTimeout="2" />

Then I put 10 seconds delay to my ashx handler's code-behind:
System.Threading.Thread.Sleep(10000); // 10 seconds

Then I commented this line:
// HttpContext.Current.Server.ScriptTimeout = 600; // 10 minutes

and opened my ashx handler's url in browser.

I expected it to crash with timeout error... but it did not happen.
:-O
Few experiments showed that executionTimeout works only if all of the following is true:
1) Domain name is not localhost (to test timeout you should use "YourComputerName" instead of "localhost").
2) Project is compiled in Release mode.
3) <compilation debug="false">
If any of the above is not true then executionTimeout length is virtually unlimited.
On top of that IIS typically times out later than executionTimeout limit asks it too.
When I set executionTimeout=2 and made my page request to sleep for 10 seconds, I was getting "Request timed out." response only in ~40% of requests.

Monday, September 13, 2010

Sneaky MaxItemsInObjectGraph attribute in WCF

I spent almost couple of days trying to figure out what caused WCF service to crash (in a weird way) when it was tried to return large resultset.
Initially the problem expressed itself on the WCF client side. When number of records in returning results was close to 5000 – WCF client generated
Meaningless "An existing connection was forcibly closed by the remote host." exception.
Google search for '"An existing connection was forcibly closed by the remote host." WCF size' brought up
WCF issues sending large data forum discussion.
The right answer (maxItemsInObjectGraph) was mentioned there, but it was buried under pile of misleading suggestions.

One step toward the solution was to use soapUI utility to make the requests (instead of calling WCF service from another .NET client).
That helped to determine that the problem is on the WCF server side -- soapUI simply couldn't get any response (when number of returning dataset rows was ~5000+).

What really helped to find the final answer -– was enabling WCF diagnostic by adding this to web.config on server side:
<system.diagnostics>
<sources>
<source name="System.ServiceModel" switchValue="Warning, ActivityTracing"
propagateActivity="true">
<listeners>
<add type="System.Diagnostics.DefaultTraceListener" name="Default">
<filter type="" />
</add>
<add name="ServiceModelTraceListener">
<filter type="" />
</add>
</listeners>
</source>
</sources>
<sharedListeners>
<add initializeData="app_tracelog.svclog"
type="System.Diagnostics.XmlWriterTraceListener, System, Version=2.0.0.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089"
name="ServiceModelTraceListener" traceOutputOptions="Timestamp">
<filter type="" />
</add>
</sharedListeners>
</system.diagnostics>
Then app_tracelog.svclog revealed much more specific error message:
---
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. '
---
Quick googling for "maxItemsInObjectGraph" brought me to MaxItemsInObjectGraph and keeping references when serializing in WCF blog post which recommended to add the following section to WCF server web.config:
<behaviors>
<serviceBehaviors>
<behavior name="LargeServiceBehavior">
<dataContractSerializer maxItemsInObjectGraph="100000"/>
</behavior>
</serviceBehaviors>
</behaviors>
and this section to WCF client web.config:
<behaviors>
<endpointBehaviors>
<behavior name="LargeEndpointBehavior">
<dataContractSerializer maxItemsInObjectGraph="100000"/>
</behavior>
</endpointBehaviors>
</behaviors>
That worked.
I used VS.NET 2008 / .NET Framework 3.5, but I think that is applicable to .NET 4.0 too.

Enjoy.

Followers

About Me

My photo
Email me: blog@postjobfree.com