Home  /  Questions  /  Question



250   96.9
Nov 04, 2010


WCF Timeout

Two questions:
  1. Looking at project 'Patterns in Action' with Windows Forms interface you find two 'app.config' files.One file is in the Windows Forms project and the other file is in the Windows Model project. Why two files?
  2. I have implemented a similar solution to 'Patterns in Action' using Windows Forms as the interface. When I return a response from the service that contains a list<DTO> with around 400 DTO objects I am getting a timeout exception from the service. If however I return a smaller list (say 200 items instead of 400 items) all is working fine. my DTO is pretty small with seven public members (int, int, string, string, string,string, string)
So far this is what I have done -
  • Ensured strings returned from the database are only a one character long each.
  • Changed all values in 'app.config' to 2147483647. For example I changed maxReceivedMessageSize="2147483647"
  • Changed all values of readerQuotas to 2147483647
  • Changed all timeout values to 10 minutes (00:10:00). For example I changed closeTimeout and sendTime in app.config files
  • Added sendTimeout = "00:10:00" to my web.config file
  • Added -
      <behaviors>
        <serviceBehaviors>
          <behavior name="behaviorAction">
            <dataContractSerializer maxItemsInObjectGraph ="2147483647"/>
          </behavior>
        </serviceBehaviors>
      </behaviors>

to both 'app.config' files and to my 'web.config' file

Whatever I do as soon as my list grows beyond 200 items it does not work.
Using the 'Service Trace Viewer' I have traced my WCF web service but could not find and hints there either.

Any help appreciated.


My 'Windows Forms Model' 'app.config' -
   - 
<?xml version="1.0" encoding="utf-8" ?> 
<configuration> 
    <system.serviceModel> 
        <bindings> 
            <wsHttpBinding> 
                <binding name="WSHttpBinding_IApplicationService" closeTimeout="00:10:00"
                    openTimeout="00:10:00" receiveTimeout="00:10:00" sendTimeout="00:10:00"
                    bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
                    maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647"
                    messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"
                    allowCookies="false"> 
                    <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647"
                        maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" /> 
                    <reliableSession ordered="true" inactivityTimeout="00:10:00"
                        enabled="true" /> 
                    <security mode="Message"> 
                        <transport clientCredentialType="Windows" proxyCredentialType="None"
                            realm="" /> 
                        <message clientCredentialType="Windows" negotiateServiceCredential="true"
                            algorithmSuite="Default" establishSecurityContext="true" /> 
                    </security> 
                </binding> 
            </wsHttpBinding> 
        </bindings> 
        <client> 
            <endpoint address="http://localhost:1274/ApplicationService.svc"
                binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IApplicationService"
                contract="ApplicationService.IApplicationService" name="WSHttpBinding_IApplicationService"> 
                <identity> 
                    <dns value="localhost" /> 
                </identity> 
            </endpoint> 
        </client> 
      <behaviors> 
        <serviceBehaviors> 
          <behavior name="behaviorAction"> 
            <dataContractSerializer maxItemsInObjectGraph ="2147483647"/> 
          </behavior> 
        </serviceBehaviors> 
      </behaviors> 
    </system.serviceModel> 
</configuration> 
 
My DTO object - 


using System; 
using System.Data; 
using System.Configuration; 
using System.Collections.Generic; 
using System.Xml.Serialization; 
using System.Linq; 
using System.Web; 
using System.Xml.Linq; 

using System.Runtime.Serialization; 

using BusinessObjects.BusinessRules; 

namespace ApplicationService.DataTransferObjects 
{ 
   [DataContract(Name = "Employee", Namespace = "http://www.yourcompany.com/types/")] 
   public class EmployeeDto 
   { 
       /// <summary>        
       /// Employee unique identifier.        
       /// </summary>        
       [DataMember] 
       public int Id { get; set; } 
       /// <summary>        
       /// Employee payroll number.        
       /// </summary>        
       [DataMember] 
       public int PayrollNumber { get; set; } 
       /// <summary>        
       /// Surname.        
       /// </summary>        
       [DataMember] 
       public string Surname { get; set; } 
       /// <summary>        
       /// Middle name.        
       /// </summary>        
       [DataMember] 
       public string MiddleName { get; set; } 

       /// <summary>        
       /// Firstname.        
       /// </summary>        
       [DataMember] 
       public string Firstname { get; set; } 

       /// <summary>        
       /// Company name of employee.        
       /// </summary>        
       [DataMember] 
       public string CompanyName { get; set; } 

       /// <summary>        
       /// Gets or sets the version number. Used for optimistic concurrency.        
       /// </summary>        
       [DataMember] 
       public string Version { get; set; } 
   } 
} 

 
Relevant section from my 'web.config' - 

  <system.serviceModel> 
     <services> 
       <service behaviorConfiguration="behaviorAction" name="ApplicationService.ServiceImplementations.ApplicationService"> 
         <endpoint binding="wsHttpBinding" bindingConfiguration="bindingAction" contract="ApplicationService.ServiceContracts.IApplicationService"> 
           <identity> 
             <dns value="localhost"/> 
           </identity> 
         </endpoint> 
         <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/> 
       </service> 
     </services> 
     <behaviors> 
       <serviceBehaviors> 
         <behavior name="behaviorAction"> 
           <serviceMetadata httpGetEnabled="true"/> 
           <serviceDebug includeExceptionDetailInFaults="true"/> 
           <dataContractSerializer maxItemsInObjectGraph ="2147483647"/> 
         </behavior> 
       </serviceBehaviors> 
     </behaviors> 
     <bindings> 
       <wsHttpBinding> 
         <binding name="bindingAction" transactionFlow="false" receiveTimeout="00:30:00" sendTimeout ="00:30:00"> 
           <reliableSession enabled="true"/> 
         </binding> 
       </wsHttpBinding> 
     </bindings> 
   </system.serviceModel> 

 
The code that generates the timeout (the timeout happens on line 'return response' at the end  - 
/// <summary>        
/// Request list of employees for a given criteria.        
/// </summary>        
/// <param name="request">Employee request message.</param>        
/// <returns>Employee response message.</returns>        
public EmployeeResponse GetEmployees(EmployeeRequest request) 
{ 
   EmployeeResponse response = new EmployeeResponse(); 
   response.CorrelationId = request.RequestId; 

   // Validate client tag, access token, and user credentials
   if (!ValidRequest(request, response, Validate.All)) 
      return response; 
   EmployeeCriteria criteria = request.Criteria as EmployeeCriteria; 
   if (request.LoadOptions.Contains("Employees")) 
   { 
      IEnumerable<Employee> employees = employeeTimesheetDao.GetEmployeeList(request.SourceDb, request.SystemDb, criteria.SiteId, criteria.FinYear, false); 
      response.Employees = employees.Select(c => Mapper.ToDataTransferObject(c)).ToList(); 
   } 
   return response; 
} 

 



250   96.9
Nov 07, 2010
I finally solved the second issue the WCF timout.
In my application I have enabled my WCF service via a COM object for legacy applications that need my WCF service.
Trouble is that COM object (being a class library) does not have app.config and so I added code to read a configuration file effectively bypassing my app.config settings. Hence the symptom that whatever I did in the app.config has no effect on the WCF service at all.

I added in the C# code, assignments for wsHttpBinding settings such as maxBufferPoolSize = 2147483647 and so forth.
Once I have done this my WCF service start working like a charm.

For those of you who are interested I have included the relevant section of my C# code.

I still do not know however why there are two app.config files in the Windows Forms project in Patterns in Action.



ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap(); 

            // Force reading configuration from a specific file in-place of the app.config that is usually used.
            fileMap.ExeConfigFilename = @"C:\Program Files\Application.exe.config";  
            Configuration config = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None); 

            // Read the endpoint from the configuration file.
            ConfigurationSectionGroup csg = config.GetSectionGroup("system.serviceModel"); 
            ConfigurationSection css = csg.Sections["client"]; 
            ClientSection cs = (ClientSection)csg.Sections["client"]; 
            ChannelEndpointElement endPoint = cs.Endpoints[0]; 
            string endPointString = endPoint.Address.ToString(); 

            // Use wsHttpBinding.
            WSHttpBinding wsBinding = new WSHttpBinding(); 
            // Enable reliable session.
            OptionalReliableSession rl = wsBinding.ReliableSession; 
            rl.Enabled = true;             
            EndpointAddress endpointAddress = new EndpointAddress(endPointString); 
            // Set values for endpoint. These values are normally set in app.config.
            // Note the max limit 2147483647 or the service will throw errors when sending back to client a large collection.
            TimeSpan ts = new TimeSpan(0, 30, 0); 
            wsBinding.ReceiveTimeout = ts; 
            wsBinding.MaxBufferPoolSize = 2147483647; 
            wsBinding.MaxReceivedMessageSize = 2147483647; 
            wsBinding.ReaderQuotas.MaxArrayLength = 2147483647; 
            wsBinding.ReaderQuotas.MaxBytesPerRead = 2147483647; 
            wsBinding.ReaderQuotas.MaxDepth = 2147483647; 
            wsBinding.ReaderQuotas.MaxStringContentLength = 2147483647; 
            wsBinding.ReaderQuotas.MaxNameTableCharCount = 2147483647; 

            // Get a new instance of the application service using the settings that were set above.
            Service = new ApplicationServiceClient(wsBinding, endpointAddress);