3
votes

I have context like that:

[EnableClientAccess()]
public class MyRiaService : LinqToEntitiesDomainService<EntityFrameworkContext>

Using Silverlight client I am initiating heavy database operation wich takes more than 1 minute. As a result I am getting timeout exception:

Uncaught Error: Unhandled Error occured in Silverlight Application: Submit operation failed. for HTTP request to https://localhost/MyProject/ClientBin/myservice.svc/binary has exceeded the allotted timeout. The time allotted to this operation may have been a portion of a longer timeout.

Stack Trace:
  at System.Windows.Ria.OperationBase.Complete(Exception error)
  at System.Windows.Ria.SubmitOperation.Complete(Exception error)
  at System.Windows.Ria.DomainContext.CompleteSubmitChanges(IAsyncResult asyncResult)
  at System.Windows.Ria.DomainContext.<>c_DisplayClassd.b_5(Object )

I would be happy to change send timeout there, but I don't know, how. I've tried this:

((WebDomainClient<LibraryDomainContext.ILibraryDomainServiceContract>)this.DomainClient).ChannelFactory.Endpoint.Binding.SendTimeout = new TimeSpan(0, 5, 0);

But I don't have property DomainClient.

1

1 Answers

3
votes

The timeout of the connection can be set on the client side on the endpoint of the domain service. But how to get hold of that? By creating an extension method for domain contexts:

public static class DomainServiceExtensions
{
    /// <summary>
    /// This method changes the send timeout for the specified 
    /// <see cref="DomainContext"/> to the specifified <see cref="TimeSpan"/>.
    /// </summary>
    /// <param name="domainContext">
    /// The <see cref="DomainContext"/> that is to be modified.
    /// </param>
    /// <param name="newTimeout">The new timeout value.</param>
    public static void ChangeTimeout(this DomainContext domainContext, 
                                          TimeSpan newTimeout)
    {
        // Try to get the channel factory property from the domain client 
        // of the domain context. In case that this property does not exist
        // we throw an invalid operation exception.
        var channelFactoryProperty = domainContext.DomainClient.GetType().GetProperty("ChannelFactory");
        if(channelFactoryProperty == null)
        {
            throw new InvalidOperationException("The 'ChannelFactory' property on the DomainClient does not exist.");
        }

        // Now get the channel factory from the domain client and set the
        // new timeout to the binding of the service endpoint.
        var factory = (ChannelFactory)channelFactoryProperty.GetValue(domainContext.DomainClient, null);
        factory.Endpoint.Binding.SendTimeout = newTimeout;
    }
}

The interesting question is when this method will be invoked. Once the endpoint is in use, the timeout can no longer be changed. So set the timeout immediately after creating the domain context:

The DomainContext-class itself is sealed, but luckily the class is also marked as partial - as is the method OnCreated() that can be extended quite easily that way.

public partial class MyDomainContext
{
    partial void OnCreated()
    {
        this.ChangeTimeout(new TimeSpan(0,10,0));
    }
}

Pro Tipp: When implementing partial classes the namespaces of all parts of the class must be identical. The code listed here belongs to the client side project (e.g. with the namespace RIAServicesExample), the partial class shown above needs to reside in the server side namespace nonetheless (e.g. RIAServicesExample.Web).