I recently got involved in tracking down the answer to an interesting issue posted on the Silverlight forums. The problem was that all WCF calls were being executed sequentially, or in other words, only one WCF call was running at a time. This was having a drastic effect on performance.
Maximum Connections?
I knew there were some limitations on the number of concurrent WCF calls that could be made. If you are using the Browser HTTP stack, your are limited by the maximum number of concurrent connections the browser is configured to make against any one server. For IE this is configured in the registry and for Firefox it is configured by typing “about:config” in the address bar and then setting the “network.http.max-connections-per-server” option.
We checked these settings and found that the browser was configured for 15 concurrent connections.
The Test Application
At this point I decided to try and replicate the issue. To do this I created a new Silverlight application and added a very simple Silverlight-enabled WCF Service.
[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class TestService
{
[OperationContract]
public void LongCall()
{
Thread.Sleep(30000);
return;
}
[OperationContract]
public void ShortCall()
{
Thread.Sleep(3000);
return;
}
}
The idea was that I would first make a call to LongCall, and then follow it shortly after with a call to ShortCall and then wait to see which one finished first. If the calls were being dispatched in parallel I would normally expect ShortCall to finish first. I quickly added the service to the client using the Add Service Reference wizard and added the following snippet of test code.
var ref1 = new TestServiceClient();
ref1.LongCallCompleted += (s ,e) => Debug.WriteLine("Long:" + DateTime.Now);
ref1.LongCallAsync();
ThreadPool.QueueUserWorkItem((o) =>
{
Thread.Sleep(5000);
ref1.ShortCallCompleted += (s, e) => Debug.WriteLine("Short:" + DateTime.Now);
ref1.ShortCallAsync();
});
I ran the code and…, good news (sort of), the short call finished well before the long call. Clearly Silverlight could make concurrent calls. So what was the problem?
Client Http Stack?
I knew the Client Http Stack (detailed here) bypassed the browser, so perhaps we could eliminate the browser as the culprit if I got the original poster to change his client to use it.
bool httpResult = WebRequest.RegisterPrefix("http://", WebRequestCreator.ClientHttp);
bool httpsResult = WebRequest.RegisterPrefix("https://", WebRequestCreator.ClientHttp);
After configuring the Client Http Stack the original poster found that his requests were now being processed concurrently! We still hadn’t isolated why the browser was only working sequentially, but we felt like we’d made progress.
Using Cookies with the Client Http Stack
Once we had changed the http stack a new problem arose, the http session was no longer begin maintained. This is because when you use the Client Http Stack its up to you to perform all cookie management. Fortunately this is relatively straight forward to fix, firstly you need configure your proxy classes to share a cookie container.
var ref1 = new TestServiceClient();
ref1.CookieContainer = SharedCookieContainer;
And then update your “.ClientConfig“ to enabled cookie containers for the binding.
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_TestService" maxBufferSize="2147483647"
enableHttpCookieContainer="true" maxReceivedMessageSize="2147483647">
<security mode="None" />
</binding>
</basicHttpBinding>
There is a good article here that covers this topic in more depth.
Things were looking good, we still didn’t know why the browser had been only allowing one request at a time, but we had a work around.
Browser Stack and Global.asax :(
Then we spotted a line in a post stating: “When using the browser HTTP stack, WCF sends requests sequentially on the same thread.”
Well, we knew this wasn’t true, because my really robust :) test application had proven it! But this no longer seemed to be an isolated issue, other people had seen it, and written about it, so what was going on?
After a bit of searching we finally found the answer. It turns out that if you have ASP.Net Session State enabled then all WCF calls made through the browsers http stack are executed sequentially. To enabled ASP.Net Session State you need to add a global.asax file to your server project that contains a session_start method. After I did this to my test project I was finally able to replicate the behaviour, problem solved!!!
Conclusion
We uncovered some pretty interesting behaviour during our problem solving session, hopefully that information is now all published in one place. Enjoy!