Two questions:
- 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?
- 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;
}