Reputation: 52745
I have a WebApi method looking more or less like this:
public async Task<HttpResponseMessage> Get(Guid id)
{
var foo = await Store.GetFooAsync(id);
if (foo.BelongsTo != User.Identity.Name)
throw new HttpResponseException(HttpStatusCode.Forbidden);
//return foo here
}
This seems to work fine in the actual application, where a custom IHttpModule
sets the principal in both HttpContext.User
and Thread.CurrentPrincipal
.
However, when calling from a unit test:
Thread.CurrentPrincipal = principal;
var response = controller.Get(id).Result;
User
is reset after await
(i.e. on the continuation), so the test fails. This happens when running under R#8, and it wasn't happening with R#7.
My workaround was to save the current principal before the first await, but it's just a hack to satisfy the test runner needs.
How can I call my controller method and make sure continuations have the same principal as the original call?
Upvotes: 4
Views: 920
Reputation: 52745
I fixed this by upgrading the MVC packages. The new version keeps the principal in ApiController.RequestContext.Principal
, separate from Thread.CurrentPrincipal
, avoiding the problem completely.
My new test code starts with:
controller.RequestContext.Principal = principal;
Upvotes: 1
Reputation: 131180
The short version is, use HttpContext.Current.Use instead of Thread.Principal.
The short version is, use Request.LogonUserIdentity or Request.RequestContext.HttpContext.User.
async/await
preserves the original request context, not the thread that started the method. This makes senses, otherwise ASP.NET would have to freeze the thread and have it available for when await
returns. The thread you run after await
is a thread from the ThreadPool, so modifying its CurrentPrincipal is a very bad idea.
Check the transcript from Scott Hanselman's podcast "Everything .NET programmers know about Asynchronous Programming is wrong" for more.
Upvotes: 0