Clive
Clive

Reputation: 1138

Why and how is MVC request thread state maintained after await on a MVC controller action?

In following code, thread id's and hashes of _uow (unit of work) are the same before and after the call to await. If the request thread is released, why does the continuation request thread have the same id? Why does the _uow object associated with the request thread have the same hash id like thread state is maintained although it was released into the thread pool?

public AccountController(IUow uow)
{
    _uow = uow;
}

public async Task<ActionResult> Sample()
{
    int id1 = Thread.CurrentThread.ManagedThreadId;
    int hash1 = _uow.GetHashCode();

    await SignInAsync(account, isPersistent: false);

    int id2 = Thread.CurrentThread.ManagedThreadId; //same as id1
    int hash2 = _uow.GetHashCode(); //same as hash1

    return Content("");
}

Upvotes: 1

Views: 422

Answers (2)

svick
svick

Reputation: 244968

In ASP.NET, you're not guaranteed to be on the the same thread after an await. But that doesn't mean you are guaranteed to be on another thread, you could still return to the same thread by chance. And you will also stay on the same thread if the Task you're awaiting has already completed when it's returned to you.

But the _uow field is a different matter: that will always stay the same in this code (assuming it's not a [ThreadStatic] field). That's because after await, you always return to the same this, that's not tied to any thread.

Actually, this is even stronger: the HttpContext.Current (and everything associated with it) will also stay the same. That's because the ASP.NET synchronization context will take care of moving the HTTP context to any new thread after await.

Upvotes: 1

noseratio
noseratio

Reputation: 61736

Two scenarios are possible here.

  • SignInAsync has executed synchronously. Try the following to see if that's the case:

    public async Task<ActionResult> Sample()
    {
        int id1 = Thread.CurrentThread.ManagedThreadId;
        int hash1 = _uow.GetHashCode();
    
        var task = SignInAsync(account, isPersistent: false);
        Debug.Print("completed synchronously: " + task.IsCompleted);
        await task;    
    
        int id2 = Thread.CurrentThread.ManagedThreadId; //same as id1
        int hash2 = _uow.GetHashCode(); //same as hash1
    
        return Content("");
    }
    
  • The same pool thread is happened to serve the rest of the request after the await continuation. It is very unlikely, but still possible, although you should never rely upon this anyway.

Upvotes: 1

Related Questions