Sooner or later, you’ll run into this, if you haven’t already: the dreaded timeout error (or NotFound error), especially with long running operations or queries. The problem? Not all timeouts are the same (to quote a famous writer: all timeouts are created equal, but some timeouts are more equal than others). An error like that can come from your binding (which has a SendTimeout property), but it can also come from your data layer: there are timeouts that can be set on your SQL commands, and on your SQL connections.
Let’s look into the binding timeout first. We’re using WCF RIA Services, so you’ll need to gain access to the binding on your endpoint. This can easily be achieved through the OnCreated method of your DomainContext, as such:
public partial class MyDomainContext { partial void OnCreated() { PropertyInfo channelFactoryProperty = this.DomainClient.GetType() .GetProperty("ChannelFactory"); if (channelFactoryProperty == null) { throw new InvalidOperationException( "There is no 'ChannelFactory' property on the DomainClient."); } ChannelFactory factory = (ChannelFactory)channelFactoryProperty .GetValue(this.DomainClient, null); factory.Endpoint.Binding.SendTimeout = new TimeSpan(0, 10, 0); } }
With this code in place (you put this where the generated DomainContext code resides – make sure you use the correct namespace, this must reside in the same namespace as your DomainContext), the SendTimeout on your binding is now set to 10 minutes: this makes sure the request can now last 10 minutes. You might notice there are other timeouts you can set here as well: CloseTimeout, OpenTimeout and ReceiveTimeout, but: SendTimeout is the one that defines the interval for the operation to complete before a timeout error is thrown.
Next on the list: the command timeout. If you’re accessing a database in your domain operation, this can timeout as well: the command timeout is what defines the maximum amount of time that’s given to the command to execute the provided SQL code (default: 60 seconds). For long running queries on your database, you will need to change this. We’re using WCF RIA Services, and let’s assume we’re also using the Entity Framework: on your DomainService, there’s an overrideable method, CreateObjectContext. This is where you can define the command timeout, as such:
protected override MyEntities CreateObjectContext() { var objectContext = base.CreateObjectContext(); objectContext.CommandTimeout = 1200; return objectContext; }
And on the the last one: connection timeout. This is the time you allow to open a connection to your database. Typically, this should be small: if it takes more than, say, a minute to open your connection, you know something is seriously wrong. But if you want to change this (the default is 15 seconds), you can do it via the connection string:
Data Source=(local);Initial Catalog=AdventureWorks; Integrated Security=SSPI;Connection Timeout=30
If you keep these 3 timeout values in mind, timeouts for (long running) operations should be a thing of the past.
Oh, one more thing: if you’re working with authentication, and your require authenticated access to your services, the authentication ticket could time out as well (you can define this value yourself), resulting in an Access Denied error. To avoid this, using sliding expiration (true by default) will already help a lot (and is a good practice for most applications). Next to that, make sure you correctly catch & handle errors of this type, by asking the user to log in again when his authentication ticket has expired. This is how this could look in your web.config file:
<authentication mode="Forms"> <forms slidingExpiration="true" timeout="180"/> </authentication>
Happy coding! 🙂