BasicHttpBinding blocking under Mono

Hosting services in Mono using the BasicHttpBinding will block incomming requests until the previous request is handled. In dotNET this is not the case. Another difference between dotNET and Mono.

I’ll demonstrate this by using a self calling service. See code below. The service will call itself when some other value than 99 is submitted.

class Program
{
    static void Main(string[] args)
    {
        // host the service
        var host = new ServiceHost(typeof(SelfService));
        host.AddServiceEndpoint(typeof(ISelfService), 
                new BasicHttpBinding(), 
                "http://localhost:666/SelfService");
        host.Open();
        try
        {
            // Subsequal calls will be blocked until this call is ready
            var result = SelfServiceProxy.CreateDefault().CallMe(0);
            Console.WriteLine(result);
        }
        catch (Exception ex)
        {
            Console.WriteLine("Main thread exception");
        }
        Console.ReadLine();
        host.Close();
    }
}

[ServiceContract]
public interface ISelfService
{
    [OperationContract]
    string CallMe(int value);
}

// serviceimplementation
public class SelfService : ISelfService
{
    public string CallMe(int value)
    {
        if (value == 99) return "Hello recursive";
        // recursive call with the correct value (will be blocked on BasicHttpBinding under Mono)
        else return SelfServiceProxy.CreateDefault().CallMe(99);
    }
}

Running this in dotNET will result in the text “Hello recursive” in the console. In Mono the execution takes a long time and eventualy prints the “Main thread exception” from the catch-block. Inspecting the exception shows it’s a System.TimeoutException.

What’s happening? The main thread proxy will call the CallMe operation with value = 0. The service will try to call itself with value = 99, the channel is opened and the request is made, but the execution is blocked by the first call (the main thread) Now whe have a deadlock, everybody is waiting for the service to complete but it can’t. Eventually the default timeout of 1 minute kicks in and the main thread gets an exception. The blocked recursive call from the service (value=99) actually gets executed, but the calling code is no longer there.

The only real solution to this problem is to use some other binding (like net.tcp) that doesn’t use the HttpListener. Or to use another address for each subsequal call but then you’ll need to know the number of subsequal requests. In my sample project I will also show the use of OperationTimeout to make the recursive call fail before the main thread fails. To set the OperationTimeOut in Mono you should hack a little bit in your proxy, see code below

public class SelfServiceProxy : ClientBase<ISelfService>, ISelfService
{
    public SelfServiceProxy(Binding binding, EndpointAddress address) : base(binding, address){}
    public static SelfServiceProxy CreateShortTimeout()
    {
        var address = new EndpointAddress("http://localhost:666/SelfService");
        var binding = new BasicHttpBinding() { ReceiveTimeout = TimeSpan.FromSeconds(4) };
        var result = new SelfServiceProxy(binding, address);
        // timeout should be set by binding ReceiveTimeout, but manual set is needed
        result.InnerChannel.OperationTimeout = TimeSpan.FromSeconds(4);
        return result;
    }    
}

The idea of setting the OperationTimeout is to use a shorter timeout for the subsequal calls than for the main thread proxy. That way the main thread will continue without an exception.

About erictummers

Working in a DevOps team is the best thing that happened to me. I like challenges and sharing the solutions with others. On my blog I’ll mostly post about my work, but expect an occasional home project, productivity tip and tooling review.
This entry was posted in Development and tagged , , , , , . Bookmark the permalink.

2 Responses to BasicHttpBinding blocking under Mono

  1. Pingback: DataContract weird characters and Mono | Erictummers's Blog

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.