DCSIMG
ASP.NET Compatible WCF services concurrency problem - Ido Flatow's Blog Veni Vidi Scripsi

Ido Flatow's Blog

Veni Vidi Scripsi

News

Have you heard me speak?
Powered
<style type='text/css' media='screen' id='sm_css'> #smix {overflow: visible;height: auto;border-radius: 10px;max-width: 250px;background-color: #323232;text-align: left;font-size: 12px;line-height: 16px;font-family:'Lucida Sans Unicode','Lucida Grande',Verdana,Arial,Helvetica,sans-serif;-webkit-border-radius: 10px;-moz-border-radius: 10px;border-radius: 10px;} #smix a {color: #0056CC;text-decoration: none;} #smix .sm_head {color: #fff; line-height: 1em;font-size: 1.4em;padding: 10px;color: #fff;} #smix .sm_lanyard_wrapper {background-color: #fff;;clear: both;width: 97%;margin: 0 auto;margin-bottom: 0px;} #smix .sm_lanyard_content {padding: 7px;}#smix button.sm_rec, #smix a.sm_rec, #smix input[type=submit].sm_rec { padding: 6px 10px; -webkit-border-radius: 2px 2px;-moz-border-radius: 2px; border-radius: 2px; border: solid 1px rgb(153, 153, 153); background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(rgb(255, 255, 255)), to(rgb(221, 221, 221))); color: #333; text-decoration: none; cursor: pointer; display: inline-block; text-align: center; text-shadow: 0px 1px 1px rgba(255,255,255,1); line-height: 1; }#smix .sm_rec:hover { background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(rgb(248, 248, 248)), to(rgb(221, 221, 221))); }#smix .sm_rec:active { background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(rgb(204, 204, 204)), to(rgb(221, 221, 221))); }#smix .sm_rec.medium { padding: 3px 7px; font-size: 13px; }#smix .sm_rec span.icon.thumbs_up {background-position: 0px 36px;vertical-align: text-top;display: inline-block;margin-right: 4px;height: 18px;width: 16px;background-image: url(http://speakermix.com/images/new/thumbsold.png);}#smix .sm_rec:hover span.icon.thumbs_up {background-position: 0px 18px;} #smix .sm_events {padding:2px 0px 4px 0px;} #smix .sm_section {font-size: 10px; border-bottom: 1px solid silver; margin-bottom: 6px;} #smix .sm_subline {font-size:120%;margin-top:4px;font-weight:bold} #smix .powered {text-align: right} #smix .powered img {margin: 7px} </style>
Sela Technology Center

Advertisement

ASP.NET Compatible WCF services concurrency problem

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.

Comments

Kevmeister said:

Hi Ida,

Do you have a reference for this information:

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.

Thanks

Kevin

# February 4, 2011 6:13 AM

Ido Flatow said:

The session lock is described in the MSDN

msdn.microsoft.com/.../aa479041.aspx

You can also look at the system.web dll with reflector to see the lock code yourself.

# February 4, 2011 9:16 AM

Steve said:

You said:

"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."

I do not believe this is true.  The default instancing mode for WCF is PerSession (that is, WCF Session).  If WCF sessions are not required for the service, then this falls back to PerCall.

blogs.msdn.com/.../wcf-instancing-mode-default-is-instancecontextmode-persession.aspx

PerCall: A new InstanceContext (and therefore service object) is created for each client request.

Furthermore, the default ConcurrencyMode for a WCF service is Single.

Single: Each instance context is allowed to have a maximum of one thread processing messages in the instance context at a time. Other threads wishing to use the same instance context must block until the original thread exits the instance context.

Therefore, in a default WCF implementation that does not require WCF Sessions, each client request will receive a single new InstanceContext.  This InstanceContext is allowed to have a maximum of one thread processing messages because of the Single ConcurrencyMode.  So, each WCF request has its own thread.  This behavior is backed by a test harness that I wrote that processes the 6 Silverlight WCF calls simultaneously within a WCF service with a default configuration.

See:

msdn.microsoft.com/.../ms731193.aspx

# June 3, 2011 5:24 PM

Ido Flatow said:

Hi Steve,

What you've written is true for WCF when the session managed by WCF is the only session. When you use ASP.NET compatibility mode, ASP.NET's session object can also be used (usually this is one of the reasons people use the compatibility mode), and in this case, ASP.NET's code that handles the session lock occurs before WCF even steps into action, meaning even if you are using per call you will still be able to see the calls run in sequence. In this case you will actually get a strange behavior where your service instance is instantiated per call, but you still share the same ASP.NET session object with the previous calls made from the same client.

# June 3, 2011 6:38 PM

Mark said:

Thank you so much. I spent hours trying to figure out what was causing my WCF service calls to hang. Turns out it was this session serialization issue.

# October 29, 2011 1:00 AM

Kir said:

What I see is that the header never contains "SOAPACTION". Could you clarify what this check is meant to do?

# January 11, 2012 3:50 PM

Ido Flatow said:

soapaction is an http header that is added to any WCF service calls that use SOAP (in contrast to RESTful calls). It is used to identify the target endpoint of the message.

# January 11, 2012 4:43 PM

Ido Flatow's Blog

Veni Vidi Scripsi

said:

This is the eighth post in the WCF 4.5 series. This post continues the previous posts on web-hosting

# February 1, 2012 9:25 PM

[??????????????] ?????? ???????????? ?? WCF 4.5? ?????????????????? ?? ???????????? ?????????????????????????? ASP.NET « ahriman' lair said:

Pingback from  [??????????????] ?????? ???????????? ?? WCF 4.5? ?????????????????? ?? ???????????? ?????????????????????????? ASP.NET &laquo; ahriman&#039; lair

# February 3, 2012 7:34 AM
Leave a Comment

(required) 

(required) 

(optional)

(required) 


Enter the numbers above: