Skip to main content

Part 2: Async requests in ASP.NET MVC 4 when working with Session [Thread Starvation my A$$]

This is a multi-part post dedicated to Async requests in ASP.NET MVC 4 when working with Session. Be sure to follow this series starting from the first post to gain a clear understanding.


Catch up from the last post

So in our last post it looked like it was Thread Starvation that was causing the all synchronous request to be queued and run sequentially. NOT! 

It wasn't Thread Starvation after all

So for thread starvation to occur, I should have exhaused all of the 5000 threads that were available. Seeing that I was hosting my application locally & was the only person accessing my website I couldn't have exhaused all my available threads (specified by MaxWorkerThreads). So we could deduce that it wasn't Thread Starvation.

What is it then?

Looks like i overlooked a key piece of information in my last post. The requests that were queuing up were all a part of the same session

How thread pools really work

On the Web server, the .NET Framework maintains a pool of threads that are used to service ASP.NET requests. When a request arrives, a thread from the pool is dispatched to process that request. If the request is processed synchronously, the thread that processes the request is blocked while the request is being processed, and that thread cannot service another request.

Access to ASP.NET session state is exclusive per session, which means that if two different users make concurrent requests, access to each separate session is granted concurrently. However, if two concurrent requests are made for the same session (by using the same SessionID value), the first request gets exclusive access to the session information. The second request executes only after the first request is finished. [Info Src Link]

What Microsoft recommends

The second session can also get access if the exclusive lock on the information is freed because the first request exceeds the lock time-out. If the EnableSessionState value in the @ Page directive is set to ReadOnly (or annotate the controller with [SessionState(SessionStateBehavior.ReadOnly)]), a request for the read-only session information does not result in an exclusive lock on the session data. However, read-only requests for session data might still have to wait for a lock set by a read-write request for session data to clear.

My solution

My original request method needed to get converted to an async operation achieved easily with async-await. In-spite of using async-await, the requests still ran sequentially due to the thread lock imposed by ASP.NET session state. Seeing that I needed access to my session state & possibly needed to save data to it, I couldn't simply disable the session state behavior. To find out what I ended up doing click here (Coming soon) (I'll include some code samples) ...

Sync v/s Async

Microsoft recommends the following ..
In general, use synchronous pipelines when the following conditions are true:
  • The operations are simple or short-running.
  • Simplicity is more important than efficiency.
  • The operations are primarily CPU operations instead of operations that involve extensive disk or network overhead. Using asynchronous action methods on CPU-bound operations provides no benefits and results in more overhead.
In general, use asynchronous pipelines when the following conditions are true:
  • The operations are network-bound or I/O-bound instead of CPU-bound.
  • Testing shows that the blocking operations are a bottleneck in site performance and that IIS can service more requests by using asynchronous action methods for these blocking calls.
  • Parallelism is more important than simplicity of code.
  • You want to provide a mechanism that lets users cancel a long-running request.

Comments

  1. Damn. .. cliffhanger for more than a year. I really wanted to know you're you solved it

    ReplyDelete

Post a Comment

Popular posts from this blog

Internet Information Services(IIS) reveals its real or internal IP Address

In the ever changing world of global data communications, inexpensive Internet connections, and fast-paced software development, security is becoming more and more of an issue. Security is now a basic requirement because global computing is inherently insecure.

Keeping that in mind, we recently ran our flagship product through a security audit. It was such a helpful exercise in tying-off any remaining lose ends in our application in terms of application security. 
Based on the security audit report, there was a relatively minor issue that appeared when accessing the /images directory of our application. Turns out that the Location response header of the 301 request returns an Internal IP address. The issue is detailed below.

Issue reportedInternet Information Services (IIS) may reveal its real or internal IP address in the Location header via a request to the /images directory. The value returned whilst pen testing is https://10.0.0.10/images.

The riskInformation regarding internal IP add…

IIS Request Filtering to block HTTP Verbs (For example Trace)

The issueRequest Filtering is a built-in security feature that was introduced in Internet Information Services (IIS) 7.0. This can be used to block specific verbs like "Trace".

When request filtering blocks an HTTP request, IIS 7 will return an HTTP 404 error to the client and log the HTTP status with a unique substatus that identifies the reason that the request was denied. Verb Denied.

HTTP SubstatusDescription404.5URL Sequence Denied404.6Verb Denied404.7File Extension Denied404.8Hidden Namespace404.1Request Header Too Long404.11URL Double Escaped404.12URL Has High Bit Chars404.13Content Length Too Large

Unit Testing HttpContext.Current.Session in MVC3 .NET

We recently changed some functionality where during the "CREATE" process, we go through a wizard to save application data. This data is saved only to the session in the final step when the user clicks the final submit.

This was easy enough to implement but when I started writing unit tests for my static methods that Add, Update, Delete or Modify the contents of our application data in the session, I got the following error:
System.NullReferenceException: Object reference not set to an instance of an object.

Turns out I had forgotten to setup the HttpContext.
The following "TestInitialise" method fixed my problem :)

[TestInitialize]
public void TestSetup()
{
// We need to setup the Current HTTP Context as follows:

// Step 1: Setup the HTTP Request
var httpRequest = new HttpRequest("", "http://localhost/", "");

// Step 2: Setup the HTTP Response
var httpResponce = new HttpResponse(new StringWriter());

// Step 3: Se…