In case you didn’t know by now, using sessions in ASP.NET will cause multiple client calls to be synchronized. This behavior, as explained in this blog post, can cause delays and timeouts in page processing, and unfortunately is not always easy to solve.
The easiest solution is to set each page’s EnableSessionState to either Enabled or ReadOnly. Pages which use session for read operations only and marked appropriately can run concurrently. Note that it is enough that one page is marked for read/write to lock the session for all concurrent pages.
BTW, changing the session state from InProc to SessionServer or SqlServer won’t solve this problem, because this behavior does not depend on the session provider.
This problem does not only apply to ASP.NET, but also to WCF services that are defined to have ASP.NET Compatibility. If you turned on the compatibility mode for your WCF service, then multiple concurrent calls from the same client, using the same channel (for example, calls from a silverlight application that are async by nature) will be synchronized and become sequential. This behavior of course requires that you use the Multiple concurrency mode instead of the default Single mode for your service, otherwise you’ll end up synchronizing requests from the client even if you don’t enable the Asp.Net compatibility mode.
What can you do?
1. Stop using the compatibility mode. Sometimes people use this mode because they want to use the session object to store session info, but there are other solution for this situation, such as using AppFabric’s Cache (AKA Velocity). If you want the compatibility mode, but don’t need the session state, just remove the Session_Start method from the Global.asax, this will disable the ability to work with sessions which will prevent the locks from happening.
2. If your WCF service only needs to read session info, you can set the session state behavior to read-only, by placing the following code in the Global.asax:
void Application_BeginRequest(object sender, EventArgs e)
{
if (Request.Headers["SOAPAction"] != null)
HttpContext.Current.SetSessionStateBehavior(SessionStateBehavior.ReadOnly);
}
As described before, if all calls are read-only calls, then there won’t be any lock on the session state and concurrent calls will run ok.
3. Another solution is to use a web farm with no sticky-session - this way every request might reach a different server (potentially), causing each server to lock only its own session state. This technique is good for several concurrent requests from a client, but if your client performs tens or hundreds of calls concurrently, this solution might not work too good.
The problem with this solution is that if you want to share the session state, you’ll need to change the state from InProc to either SqlServer or StateServer (or the customized Appfabric cache). Because session state is unique to an appdomain, you’ll have to do “tweak” you application to allow the state manager to treat both app pools the same:
a. Use the same machine key for both servers / websites.
b.If you manage your state using SqlServer, you might need to change the stored procedure that identifies the application using this technique, or this technique. If you manage your state using StateService, you’ll can use this technique (tested successfully on IIS 7).
To conclude, using the AspNet compatibility mode and keeping sessions can harm your WCF service’s ability to handle concurrent calls from the same client. There are several solution, and you’ll have to pick the right one for you.