17

I have a Web API Controller with the following method inside:

public string Tester()
{
    Thread.Sleep(2000);

    return "OK";
}

When I call it 10 times (Using Fiddler), I expect all 10 calls to return after ~ 2 seconds. However the calls return after 2,4,8...20 seconds, respectively. What is blocking it from running concurrently? How do I fix that?

Do regular Controllers behave the same as web-api controllers?

Elad Katz
  • 7,483
  • 5
  • 35
  • 66
  • I will go ahead and assume that you're using an ApiController in an MVC.NET project, 'cause if that's not the case, you shouldn't be experiencing what you describe unless perhaps if you're explicitly accessing some "blocking resource". Please update your question to include some information that clarifies, and look at @Badri's answer as well. – Oskar Lindberg Nov 07 '14 at 07:56

5 Answers5

19

What you describe matches the default behavior of the ASP.NET Session State and can be solved by disabling it in web.config.

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. (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, 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.

Source: ASP.NET Session State Overview

sisve
  • 19,501
  • 3
  • 53
  • 95
8

I don't think I'm answering your question but what I'd like to write here is too big for a comment.

First up, ASP.NET Web API has nothing to do with session state. In fact, if session has to be used with web API, then it needs to be explicitly enabled.

Now, I have the same exact API controller like you and I host it in IIS. If I make concurrent requests, it is running the requests in parallel and not serially. Here is how I tested from Fiddler.

First, I made a GET to the API and waited for 200 status code (#1 in Fiddler left pane). Then, I selected #1 and pressed U to replay the same request unconditionally 9 times. With that I have 10 requests in the left pane (#1 through #10). Then, I selected all 10 of them and pressed R to reissue all the ten requests in parallel. I then selected requests 11 through 20 in the left pane and went to Timeline tab. I see this graph.

PS. I tested the web API running locally, BTW.

enter image description here

Next, I wanted to log the time stamp request as received by the action method. So, I modified action method to return a string like this.

public string Get()
{
    string ts = DateTime.Now.ToString("mm:ss.fff");
    Thread.Sleep(2000);
    return ts;
}

I got the following.

00:43.795
00:43.795
00:45.812
00:44.517
00:43.795
00:43.795
00:45.515
00:43.795
00:43.795
00:43.795

To me this means, all the requests are running in parallel.

  • 1
    Does session-state really have to be enabled explicitly if it's already enabled in web.config? The SessionModule will load (as a default configuration) and will perform the locking unless the -configuration is changed. Perhaps a web-api project comes with a default-config that disables session-state? And the OP added a web-api controller to a default mvc-project (which has enabled session-state)? – sisve Nov 08 '14 at 06:50
  • 3
    Its ok that web api is not linked with session and you are experimenting with no session mode . Can you test your scenarios when sessions are enabled . You must then be getting requests in sequence rather than parallel.Can you kindly confirm that – irfan Munir Nov 20 '14 at 05:58
6

Look at this question, which is relative to your problem: Are all the web requests executed in parallel and handled asynchronously?

It states that:

A webApi service, by default, executes all its incoming requests in parallel, but only if the current multiple requests (at a certain time) came from different sessions. That is to say, if single client will send some simultaneously requests to server, all of them will be executed sequentially and won't be executed concurrently.

To solve this, you can use async methods, as described here.

Generally, you need to declare your method as async, like this:

public async Task<MyObj> GetObj()
Community
  • 1
  • 1
Mark Segal
  • 5,427
  • 4
  • 31
  • 69
  • Do regular controllers behave the same (namely, do they sequential same-session requests?) – Elad Katz Nov 04 '14 at 13:38
  • 1
    You mean an MVC controller? Yes. Read more here http://weblogs.asp.net/imranbaloch/concurrent-requests-in-asp-net-mvc – Mark Segal Nov 04 '14 at 13:42
  • do different controllers block each other? (if I understand correctly from the article) – Elad Katz Nov 04 '14 at 15:08
  • 1
    @EladKatz It's not a question of whether you use a Controller or an ApiController, but rather a question of whether you (potentially) try to access a "blocking resource" or not. If you can't make the resource "non-blocking" (like in the case of the ASP.NET Session State see the "make it read-only" part of Simon Svensson's answer) you can go for the `async` option (or another parallelization technique) as suggested. – Oskar Lindberg Nov 07 '14 at 08:13
  • 2
    The statement Mark is quoting in his answer is not entirely accurate, as it does not apply to an actual WebApi-solution (as opposed to when using a ApiController within an MVC.NET solution). Having this one marked as "correct" may be misleading people (mostly because the question lacks some background information) into believing that the WebApi is necessarily dependent on session state by default - which it is obviously not. See also the answer from @Badri. – Oskar Lindberg Nov 07 '14 at 08:29
  • It looks that by default sessions are disabled in WEB API and as @Mark pointed out that in case of new (no) session system will run in parallel and for this reason Badri is getting parallel response. So whenever one enables the session in web api his api controller will behave like sync method calls and run in sequentially. To make parallel requests for session enabled web api it could require to use async or is there any other solution? – irfan Munir Nov 18 '14 at 08:40
  • 1
    not sure in web api but in MVC, use async action still blocks concurrent requests from one same session. – Hopeless Apr 04 '19 at 10:28
3

You must have enabled the Session State somewhere for Web Api. Web API is restful by default and has no session. Check your global.asax Application_AuthenticateRequest section (this is where I enable session state for Web Api). Find where you enabled your session state at and set it to read-only mode to allow for parallelism on web methods using session state. See this question which is similar: Web API Service - How to make the requests at the server to be executed concurrently

Look for something like this:

HttpContext.Current.SetSessionStateBehavior(System.Web.SessionState.SessionStateBehavior.Required);

Change it to this:

HttpContext.Current.SetSessionStateBehavior(System.Web.SessionState.SessionStateBehavior.ReadOnly);
Timothy Gonzalez
  • 1,802
  • 21
  • 18
1

Try use this instead:

public async Task<string> Tester()
{

    await Task.Delay(2000);
    return "OK";
}

See this to know the difference between Task.Delay vs Thread.Sleep which blocks http://social.technet.microsoft.com/wiki/contents/articles/21177.visual-c-thread-sleep-vs-task-delay.aspx

Omar.Alani
  • 4,050
  • 2
  • 20
  • 31