开发者

.NET webservice call pooling?

I am writing acceptance tests to validate a system and it's data access is all done through web service calls.

Unfortunately, because I make so many calls, so quickly, I run into the following error

System.Net.Sockets.SocketException: Only one usage of each socket address (protocol/network address/port) is normally permitted

I have locally cached as many of the calls as possible, but that's not enough. I can't fake or mock these calls. They have to be real for this level of tests to be valid.

Is there a way to get repeated frequent web service calls to pool?

Or to check if a connection can be made to the service prior to attempting the call, and wait until an available socket exists?

In production the calls are never made at this speed, so the issue won't arise...but it would be nice to have some code in place to allow for the tests to work, and throttle or share the c开发者_如何学编程onnections.

Thanks


Turns out, a co-worker had a solution already that was used on our e-com site. You just inherit from your web-service, override the GetWebRequest function with some different settings and you're done.

class SafeMyWebService : MyWS.Service
{
    private static int _lastBindPortUsed;

    protected override WebRequest GetWebRequest(Uri uri)
    {
        var webreq = base.GetWebRequest(uri) as HttpWebRequest;

        webreq.KeepAlive = true;
        webreq.ProtocolVersion = HttpVersion.Version10;
        webreq.ServicePoint.MaxIdleTime = 10 * 1000; // milliseconds 
        webreq.ServicePoint.BindIPEndPointDelegate = new BindIPEndPoint(BindIPEndPointCallback);
        webreq.Timeout = 2000;
        webreq.ConnectionGroupName = "MyConnectionGroupName";

        return webreq;
    }

    public static IPEndPoint BindIPEndPointCallback(ServicePoint servicePoint, IPEndPoint remoteEndPoint, int retryCount)
    {
        int port = Interlocked.Increment(ref _lastBindPortUsed);
        Interlocked.CompareExchange(ref _lastBindPortUsed, 5001, 65534);

        return remoteEndPoint.AddressFamily == AddressFamily.InterNetwork 
            ? new IPEndPoint(IPAddress.Any, port) 
            : new IPEndPoint(IPAddress.IPv6Any, port);
    }

}

I'm guessing it uses more resources, but it doesn't fail.


The MSDN Article Avoiding TCP/IP Port Exchastion recommends the following approaches

  • Increase the number of ephemeral ports available via the registry (that is, the ports allocated on the client to call the webservice
  • Reduce the TCP/IP timeout to free ports more quickly (again via the registry).

You should also check that you're closing the connections correctly after each call in the teardown of the test.

Alternativly, if you don't want to make any config changes, you could scan the ephemeral port range and if there are no ports free, pause and wait for some to be released. The article 'Detecting the next available, Free TCP port' has some example code that could be adapted for this purpose.


A simple solution would be to slow down your tests by making you thread sleep for a short time; faster than would be in production but shorter than what would use up all the ports.

No change in the app or the system.

0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜