Silverlight, Wcf Services in ASP.Net Compatibility Mode and Threading

At work I recently stumbled across an interesting issue when consuming IIS hosted wcf services from a silverlight 3 application. At startup the application was calling 3 functions on a service simultaneously, however when inspecting the traffic in Fiddler, only two requests were executed, and the third followed when one of the two requests returned. I had this behaviour on IE7. My first idea was that this is a browser setting (connections per server) and I was proven right.

This article explains, how to raise the limit. Later versions of IE seem to come with different defaults. However after doing the registry change makes all requests start simultaneously. However the duration of the three calls somehow suggested that they were not processed at the same time or that there was some kind of locking issue.

One problem that was part of the later solution is, that we did not specify concurrency and instance context mode for our services. The defaults are one instance per session and onesimultaneous call per instance. Unfortunately changing this by applying a ServiceBehavior attribute did not change a thing.

I searched our own code for placed where a locking issue could occur but found nothing. When setting breakpoints on the service operations it turned out that these were indeed called sequentially and - even more interestingly - on the same thread. We use forms authentication for our application, the session token additionally attached to the soap header of service calls. Because of the AspNet compatibility mode of wcf services, IIS can associate service calls with existing Asp.Net sessions. In a later test i found out that the sequential behaviour seems to be happening on a per user basis. When having 2 simultaneous user log in, they sequentialize their own requests, but execute parallel in contrast to the other user.

Removing the compatibility mode from the Wcf services (which is a theoretical option since the token is part of the soap header as well) solves the problem. Wcf calls will be dispatched on different threads with no delay. However we still wanted the option to run in compatible mode, so I kept searching, wether someone had the same issue.

Finally this article saved my day. The first thing you need to know to understand the issue is, what the Asp.Net compatibility mode does. Wcf without this mode bypasses the complete http pipeline which is used to handle IIS requests for regular Asp.net applications. The result of this is you you do not have the concept of a Http context and things related to it like a session. The compatibility mode just links the wcf handling into the IIS pipeline which allows plugging in custom modules and handling things like authentication outside the service call. When running a web application with forms authentication, Asp.Net will watch out for a session cookie and retrieve a reference to a user session, if it's validly associated with one. To prevent several requests inside the session from tampering with shared data, Asp.Net will lock on the session object at an early state of the request. This will somehow slow down performance per user, however for web applications this is mostly unnotable. Unfortunately, when running Wcf services in compatibility mode you face the same behaviour. Wcf appears to dispatch all service calls on the same thread because of a locked session object. The point where the decision is made ot sequentialize requests is, when a valid session cookie was identified. If no such cookie is available, everything is fine since no locking happens.

When calling services from a silverlight application, there is no direct way to tell the service client to not include the session cookie - at least when using the browser stack - however you can use the "client stack" which is a new feature of silverlight 3. To use the client stack, register it with the protocol used: 

WebRequest.RegisterPrefix ("http://", System.Net.Browser.WebRequestCreator.ClientHttp);

If you need this to work and service requests need to be associated with a session, you need to make this connection manually (like we did using a soap header).

All this took me really long to figure out and was extremely annoying. I hope this article helps you when facing similar issues.

 

About the author

for comments and suggestions contact:

 

Month List