开发者

How to fix basicHttpBinding in WCF when using multiple proxy clients?

[Question seems a little long but please have patience. It has sample source to explain the problem.]

Consider following code which is essentially a WCF host:

[ServiceContract (Namespace = "http://www.mightycalc.com")]
interface ICalculator
{
    [OperationContract]
    int Add (int aNum1, int aNum2);
}

[ServiceBehavior (InstanceContextMode = InstanceContextMode.PerCall)]
class Calculator: ICalculator
{
    public int Add (int aNum1, int aNum2) {
        Thread.Sleep (2000); //Simulate a lengthy operation
        return aNum1 + aNum2;
    }
}

class Program
{
    static void Main (string[] args) {
        try {
            using (var serviceHost = new ServiceHost (typeof (Calculator))) {
                var httpBinding = new BasicHttpBinding (BasicHttpSecurityMode.None);
                serviceHost.AddServiceEndpoin开发者_运维知识库t (typeof (ICalculator), httpBinding, "http://172.16.9.191:2221/calc");

                serviceHost.Open ();
                Console.WriteLine ("Service is running. ENJOY!!!");
                Console.WriteLine ("Type 'stop' and hit enter to stop the service.");
                Console.ReadLine ();

                if (serviceHost.State == CommunicationState.Opened)
                    serviceHost.Close ();
            }
        }
        catch (Exception e) {
            Console.WriteLine (e);
            Console.ReadLine ();
        }
    }
}

Also the WCF client program is:

class Program
{
    static int COUNT = 0;
    static Timer timer = null;

    static void Main (string[] args) {
        var threads = new Thread[10];

        for (int i = 0; i < threads.Length; i++) {
            threads[i] = new Thread (Calculate);
            threads[i].Start (null);
        }

        timer = new Timer (o => Console.WriteLine ("Count: {0}", COUNT), null, 1000, 1000);
        Console.ReadLine ();
        timer.Dispose ();
    }

    static void Calculate (object state)
    {
        var c = new CalculatorClient ("BasicHttpBinding_ICalculator");
        c.Open ();

        while (true) {
            try {
                var sum = c.Add (2, 3);
                Interlocked.Increment (ref COUNT);
            }
            catch (Exception ex) {
                Console.WriteLine ("Error on thread {0}: {1}", Thread.CurrentThread.Name, ex.GetType ());
                break;
            }
        }

        c.Close ();
    }
}

Basically, I am creating 10 proxy clients and then repeatedly calling Add service method on separate threads. Now if I run both applications and observe opened TCP connections using netstat, I find that:

  • If both client and server are running on same machine, number of tcp connections are equal to number of proxy objects. It means all requests are being served in parallel. Which is good.
  • If I run server on a separate machine, I observed that maximum 2 TCP connections are opened regardless of the number of proxy objects I create. Only 2 requests run in parallel. It hurts the processing speed badly.
  • If I switch to net.tcp binding, everything works fine (a separate TCP connection for each proxy object even if they are running on different machines).

I am very confused and unable to make the basicHttpBinding use more TCP connections. I know it is a long question, but please help!


After spending 2 days on this problem, I found the solution so let me document it here.

Actually the problem is not of service configuration or throttling. Actually server (WCF host) cannot do anything if a client is not making connection to it. In this case WCF client was not making more than 2 connections. I tried basicHttpBinding, WsHttpBinding and even the good old web reference (asmx) method. Every case failed to make more than 2 connections.

The root of this effect lies in ServicePointManager.DefaultConnectionLimit property which has a default value of 2. This class is in System.Net namespace which is responsible for making Http connections. Apparently both WCF and ASMX web reference use System.Net namespace for doing their HTTP stuff. This explains why I couldn't make multiple service request even after creating multiple proxy clients in multiple threads.

In summary, the solution is to set ServicePointManager.DefaultConnectionLimit to the number of concurrent calls you want to make from your client.


Check out server throttling - it's a server-side behavior which you can apply to your server-side config:

<system.serviceModel>
    <services>
      <service 
        name="Microsoft.WCF.Documentation.SampleService"
        behaviorConfiguration="Throttled" >
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8080/SampleService"/>
          </baseAddresses>
        </host>
        <endpoint
          address=""
          binding="wsHttpBinding"
          contract="Microsoft.WCF.Documentation.ISampleService"
         />
        <endpoint
          address="mex"
          binding="mexHttpBinding"
          contract="IMetadataExchange"
         />
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="Throttled">
          <serviceThrottling 
            maxConcurrentCalls="1" 
            maxConcurrentSessions="1" 
            maxConcurrentInstances="1" />
          <serviceMetadata httpGetEnabled="true" httpGetUrl="" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>

See this blog post for more detailed info, or check the MSDN docs on Service Throttling

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜