I have a method that uses a repository (userRepo
):
public override Task<IdentityResult> CreateLocalUserAsync(IUser user, string password, CancellationToken cancellationToken)
{
var task = new Task<IdentityResult>(() => {
TUserEntity newUser = new TUserEntity
{
Id = user.Id,
UserName = user.UserName,
Password = password
};
userRepo.Save(newUser).Flush();
return new IdentityResult(true);
}, cancellationToken);
task.Start();
return task;
}
The userRepo
object has a dependency that uses HttpContext.Current
. Both of these are resolved using ninject InRequestScope
.
The above method is called inside the default AccountController
in Mvc 5:
var result = await IdentityManager.Users.CreateLocalUserAsync(user, model.Password);
I have tried adding this setting to web.config:
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
Also, I am definitely using .NET 4.5. This is also in my web.config:
<httpRuntime targetFramework="4.5" />
It is not possible to get the information from the HttpContext
before I start the task because a dependency of the userRepo
in the task is using the information and both objects are resolved using Ninject.
How can I ensure that HttpContext.Current
will not be null?
The "task friendly sync context" here applies to the continuation from the await
: whatever you do with result
, it will have the http-context. It does not, however, relate to task.Start
. That relates to the TaskScheduler
, not the sync-context.
Basically, by performing this on a worker, you are (in the process, as a consequence) divorcing that worker from the http-context. You must either:
Personally, I doubt you're gaining much by pushing this onto a worker. If you really want to go async
, the ideal would be for your repo to internally support *Async
methods. That requires more than using threads: it usually means architectural changes, for example, using async SQL methods. Something written from the ground up to use async
and sync-context-aware continuations (aka await
) would automatically preserve things like the http-context.
The important difference here is that an async
/await
implementation is linear but not continuous, i.e.
<===(work)==>
<===(callback; more work)===>
<===(another callback)===>
where-as your existing code potentially performs things in parallel, i.e.
<==========(original work)=================>
<===========(task on worker thread)=============>
The fact that the async
/await
approach is basically linear makes it far more suitable for access to things like http-context, since it knows that (done right) there will only be one thread at a time accessing it - even if it isn't the same thread end-to-end.